akquant 0.2.51__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.2/.gitignore +49 -0
- {akquant-0.2.51 → akquant-0.3.2}/CHANGELOG.md +1 -0
- {akquant-0.2.51 → akquant-0.3.2}/Cargo.lock +3 -3
- {akquant-0.2.51 → akquant-0.3.2}/Cargo.toml +1 -1
- {akquant-0.2.51 → akquant-0.3.2}/PKG-INFO +4 -4
- {akquant-0.2.51 → akquant-0.3.2}/README.md +3 -3
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/advanced/live_functional_quickstart.md +6 -4
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/advanced/llm.md +2 -2
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/advanced/warm_start.md +2 -2
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/guide/examples.md +1 -1
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/guide/strategy.md +7 -7
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/reference/api.md +12 -11
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/start/quickstart.md +2 -2
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/textbook/07_futures.md +2 -2
- akquant-0.3.2/docs/zh/advanced/adding_a_broker.md +245 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/advanced/live_functional_quickstart.md +5 -4
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/advanced/llm.md +2 -2
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/advanced/multi_timeframe_feed_api.md +49 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/advanced/warm_start.md +2 -2
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/guide/examples.md +5 -5
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/guide/strategy.md +63 -12
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/reference/api.md +8 -8
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/start/quickstart.md +2 -2
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/textbook/00_glossary.md +1 -1
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/textbook/05_strategy.md +3 -3
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/textbook/07_futures.md +2 -2
- {akquant-0.2.51 → akquant-0.3.2}/examples/06_complex_orders.py +1 -1
- {akquant-0.2.51 → akquant-0.3.2}/examples/21_warm_start_demo.py +2 -2
- {akquant-0.2.51 → akquant-0.3.2}/examples/36_trailing_orders.py +6 -2
- {akquant-0.2.51 → akquant-0.3.2}/examples/39_live_broker_submit_order_demo.py +12 -2
- {akquant-0.2.51 → akquant-0.3.2}/examples/42_live_broker_event_audit_demo.py +1 -1
- {akquant-0.2.51 → akquant-0.3.2}/examples/43_target_weights_rebalance.py +1 -1
- {akquant-0.2.51 → akquant-0.3.2}/examples/59_akshare_etf_rotation.py +2 -2
- akquant-0.3.2/examples/65_bar_generator.py +126 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/README.md +4 -4
- {akquant-0.2.51 → akquant-0.3.2}/examples/strategies/08_target_positions_long_short.py +4 -4
- {akquant-0.2.51 → akquant-0.3.2}/examples/strategies/README.md +2 -2
- {akquant-0.2.51 → akquant-0.3.2}/examples/textbook/ch09_portfolio.py +1 -1
- {akquant-0.2.51 → akquant-0.3.2}/pyproject.toml +2 -1
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/__init__.py +8 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/akquant.pyi +1 -1
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/backtest/engine.py +20 -21
- akquant-0.3.2/python/akquant/bar_generator.py +134 -0
- akquant-0.3.2/python/akquant/execution/__init__.py +1 -0
- akquant-0.3.2/python/akquant/execution/base.py +49 -0
- akquant-0.3.2/python/akquant/execution/sim.py +69 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/gateway/__init__.py +8 -0
- akquant-0.3.2/python/akquant/gateway/broker_event_adapter.py +260 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/gateway/broker_event_bridge.py +54 -2
- akquant-0.3.2/python/akquant/gateway/broker_execution.py +273 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/gateway/broker_models.py +46 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/gateway/broker_recovery.py +4 -1
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/gateway/broker_runtime.py +41 -0
- akquant-0.3.2/python/akquant/gateway/broker_state_cache.py +112 -0
- akquant-0.3.2/python/akquant/gateway/broker_strategy_api.py +124 -0
- akquant-0.3.2/python/akquant/gateway/brokers/builtins.py +85 -0
- akquant-0.3.2/python/akquant/gateway/brokers/plugins.py +30 -0
- akquant-0.3.2/python/akquant/gateway/factory.py +27 -0
- akquant-0.3.2/python/akquant/gateway/local_stop_book.py +153 -0
- akquant-0.3.2/python/akquant/gateway/order_receipt.py +60 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/gateway/order_submitter.py +178 -39
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/gateway/protocols.py +1 -1
- akquant-0.3.2/python/akquant/gateway/trader_base.py +90 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/live.py +240 -17
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/strategy.py +317 -204
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/strategy_events.py +16 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/strategy_framework_hooks.py +78 -3
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/strategy_trading_api.py +491 -453
- {akquant-0.2.51 → akquant-0.3.2}/src/pipeline/stages/shared.rs +18 -12
- {akquant-0.2.51 → akquant-0.3.2}/tests/gateway_contract/test_event_bridge_contract.py +5 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/gateway_contract/test_submitter_contract.py +12 -15
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/current/futures_margin/equity_curve.parquet +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/current/futures_margin/metrics.json +1 -1
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/current/futures_margin/orders.parquet +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/current/option_basic/equity_curve.parquet +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/current/option_basic/metrics.json +1 -1
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/current/option_basic/orders.parquet +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/current/stock_t1/equity_curve.parquet +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/current/stock_t1/metrics.json +1 -1
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/current/stock_t1/orders.parquet +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/current/stock_t1/trades.parquet +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_account_risk_rules.py +1 -1
- akquant-0.3.2/tests/test_api_rename_cash.py +9 -0
- akquant-0.3.2/tests/test_api_rename_composites.py +13 -0
- akquant-0.3.2/tests/test_api_rename_equity.py +9 -0
- akquant-0.3.2/tests/test_api_rename_holding_bars.py +9 -0
- akquant-0.3.2/tests/test_api_rename_positions.py +15 -0
- akquant-0.3.2/tests/test_api_rename_rebalance.py +11 -0
- akquant-0.3.2/tests/test_bar_generator.py +296 -0
- akquant-0.3.2/tests/test_broker_bridge_adapts_events.py +140 -0
- akquant-0.3.2/tests/test_broker_bridge_drives_order_groups.py +72 -0
- akquant-0.3.2/tests/test_broker_event_adapter.py +186 -0
- akquant-0.3.2/tests/test_broker_event_adapter_local_id.py +46 -0
- akquant-0.3.2/tests/test_broker_execution_local_stops.py +168 -0
- akquant-0.3.2/tests/test_broker_execution_read_path_parity.py +173 -0
- akquant-0.3.2/tests/test_broker_execution_stop_requeue.py +103 -0
- akquant-0.3.2/tests/test_broker_plugins.py +87 -0
- akquant-0.3.2/tests/test_broker_position_sync.py +115 -0
- akquant-0.3.2/tests/test_broker_seed_baseline.py +168 -0
- akquant-0.3.2/tests/test_broker_trade_redelivery_dedup.py +122 -0
- akquant-0.3.2/tests/test_close_position_delegate.py +86 -0
- akquant-0.3.2/tests/test_composed_ctx_not_ready.py +158 -0
- akquant-0.3.2/tests/test_cost_config_consolidation.py +110 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_engine.py +2 -2
- akquant-0.3.2/tests/test_event_model_parity.py +73 -0
- akquant-0.3.2/tests/test_execution_binding.py +18 -0
- akquant-0.3.2/tests/test_execution_broker.py +146 -0
- akquant-0.3.2/tests/test_execution_broker_reads_routed.py +144 -0
- akquant-0.3.2/tests/test_execution_composed_parity.py +45 -0
- akquant-0.3.2/tests/test_execution_read_delegation.py +26 -0
- akquant-0.3.2/tests/test_execution_sim.py +53 -0
- akquant-0.3.2/tests/test_execution_write_delegation.py +40 -0
- akquant-0.3.2/tests/test_gateway_broker_live_cancel.py +146 -0
- akquant-0.3.2/tests/test_gateway_broker_live_reads.py +82 -0
- akquant-0.3.2/tests/test_gateway_broker_models_ext.py +90 -0
- akquant-0.3.2/tests/test_gateway_broker_state_cache.py +59 -0
- akquant-0.3.2/tests/test_gateway_broker_state_invalidation.py +130 -0
- akquant-0.3.2/tests/test_gateway_broker_submitter_readiness.py +62 -0
- akquant-0.3.2/tests/test_gateway_broker_submitter_signature.py +152 -0
- akquant-0.3.2/tests/test_gateway_builtins_registry.py +23 -0
- akquant-0.3.2/tests/test_gateway_optional_market.py +15 -0
- akquant-0.3.2/tests/test_gateway_order_submitter_extra.py +216 -0
- akquant-0.3.2/tests/test_gateway_sim_submit_guard.py +68 -0
- akquant-0.3.2/tests/test_gateway_tif_mapping.py +25 -0
- akquant-0.3.2/tests/test_gateway_trader_base.py +63 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_live_runner_broker_bridge.py +199 -26
- akquant-0.3.2/tests/test_live_runner_broker_readiness.py +109 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_live_runner_broker_recovery.py +3 -1
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_live_runner_broker_submitter.py +23 -20
- akquant-0.3.2/tests/test_live_runner_order_request_cache.py +89 -0
- akquant-0.3.2/tests/test_live_runner_stop_remap.py +44 -0
- akquant-0.3.2/tests/test_local_stop_book.py +122 -0
- akquant-0.3.2/tests/test_local_stop_book_threadsafe.py +53 -0
- akquant-0.3.2/tests/test_local_stop_scenario.py +78 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_multisymbol_cross_section_consistency.py +22 -22
- akquant-0.3.2/tests/test_oco_bracket_broker_live_scenario.py +103 -0
- akquant-0.3.2/tests/test_on_execution_report_noop.py +10 -0
- 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.2/tests/test_removed_wrappers.py +9 -0
- akquant-0.3.2/tests/test_review_minors_cleanup.py +78 -0
- akquant-0.3.2/tests/test_stop_id_remap_scenario.py +78 -0
- akquant-0.3.2/tests/test_strategy_events_stop_hook.py +38 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_strategy_extras.py +93 -65
- akquant-0.3.2/tests/test_strategy_order_group_lock.py +55 -0
- akquant-0.3.2/tests/test_strategy_sizing_broker_live_guard.py +159 -0
- akquant-0.3.2/tests/test_target_orders_core.py +65 -0
- akquant-0.2.51/.gitignore +0 -35
- akquant-0.2.51/python/akquant/gateway/factory.py +0 -105
- {akquant-0.2.51 → akquant-0.3.2}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/.github/workflows/deploy-docs.yml +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/.github/workflows/docs-quality.yml +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/.github/workflows/release.yml +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/.pre-commit-config.yaml +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/CODE_OF_CONDUCT.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/CONTRIBUTING.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/LICENSE +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/assets/dashboard_preview.png +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/assets/logo.svg +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/assets/social_preview.png +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/CNAME +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/assets/akquant-icon.svg +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/assets/akquant-logo.svg +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/assets/reports/akquant_report.html +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/advanced/analyzer_plugin_spec.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/advanced/broker_capability_matrix.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/advanced/custom_broker_production_checklist.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/advanced/custom_broker_registry.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/advanced/data_feed_adapter_spec.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/advanced/ml.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/advanced/multi_strategy_guide.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/advanced/multi_timeframe_feed_api.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/advanced/runtime_config.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/advanced/strategy_style_decision.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/advanced/timezone.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/guide/analysis.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/guide/cross_section_checklist.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/guide/custom_indicator.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/guide/data.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/guide/factor.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/guide/indicator_scenario_quickref.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/guide/optimization.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/guide/python_basics.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/guide/quant_basics.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/guide/rust_indicator_reference.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/guide/talib_indicator_playbook.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/guide/testing.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/guide/visualization.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/index.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/meta/architecture.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/meta/internals.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/start/first_strategy.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/start/installation.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/start/setup_guide.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/textbook/01_foundations.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/textbook/02_programming.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/textbook/03_data.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/textbook/04_backtest_engine.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/textbook/05_strategy.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/textbook/06_stock_a.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/textbook/08_options.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/textbook/09_funds.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/textbook/10_analysis.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/textbook/11_optimization.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/textbook/12_ml.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/textbook/13_visualization.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/textbook/14_factor.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/textbook/15_live_trading.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/textbook/16_rust_indicators.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/en/textbook/index.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/javascripts/mathjax.js +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/javascripts/search-lang-filter.js +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/robots.txt +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/advanced/analyzer_plugin_spec.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/advanced/broker_capability_matrix.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/advanced/custom_broker_production_checklist.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/advanced/custom_broker_registry.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/advanced/data_feed_adapter_spec.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/advanced/ml.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/advanced/multi_strategy_guide.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/advanced/runtime_config.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/advanced/strategy_style_decision.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/advanced/timezone.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/guide/analysis.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/guide/cross_section_checklist.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/guide/custom_indicator.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/guide/data.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/guide/factor.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/guide/indicator_scenario_quickref.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/guide/optimization.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/guide/python_basics.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/guide/quant_basics.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/guide/rust_indicator_reference.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/guide/talib_indicator_playbook.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/guide/testing.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/guide/visualization.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/index.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/meta/architecture.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/meta/internals.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/start/first_strategy.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/start/installation.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/start/setup_guide.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/textbook/01_foundations.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/textbook/02_programming.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/textbook/03_data.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/textbook/04_backtest_engine.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/textbook/06_stock_a.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/textbook/08_options.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/textbook/09_funds.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/textbook/10_analysis.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/textbook/11_optimization.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/textbook/12_ml.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/textbook/13_visualization.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/textbook/14_factor.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/textbook/15_live_trading.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/textbook/16_rust_indicators.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/textbook/ROADMAP.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/textbook/appendix_cite.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/textbook/appendix_pitfalls.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/textbook/appendix_setup.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/textbook/capstone.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/docs/zh/textbook/index.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/01_quickstart.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/02_parameter_optimization.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/03_parameter_optimization_advanced.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/04_mixed_assets.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/05_live_trading_ctp.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/07_option_test.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/08_event_callbacks.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/09_ml_framework.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/10_ml_walk_forward.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/11_plot_visualization.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/12_wfo_integrated.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/13_quantstats_report.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/14_multi_frequency.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/15_plot_intraday.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/16_adj_returns_signal.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/17_readme_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/18_benchmark_multisymbol.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/19_factor_expression.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/20_risk_management_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/22_strategy_runtime_config_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/23_functional_callbacks_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/24_functional_tick_simulation_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/25_streaming_backtest_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/26_streaming_quickstart.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/27_streaming_monitoring_console.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/28_streaming_alerts_and_persist.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/29_streaming_event_report.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/30_streaming_report_oneclick.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/31_streaming_live_console.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/32_streaming_live_web.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/33_report_and_analysis_outputs.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/34_multi_strategy_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/35_custom_broker_registry_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/37_feed_replay_alignment_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/38_live_functional_strategy_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/40_functional_multi_slot_risk_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/41_live_multi_slot_orchestration_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/44_strategy_source_loader_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/45_talib_indicator_playbook_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/46_broker_profile_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/47_margin_liquidation_audit_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/48_margin_liquidation_priority_compare.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/49_on_expiry_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/50_framework_hooks_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/51_class_tick_callbacks_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/52_pre_open_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/53_timer_to_pre_open_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/54_functional_pre_open_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/55_functional_ml_walk_forward.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/56_functional_warm_start_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/57_functional_multi_slot_warm_start_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/58_incremental_bootstrap_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/60_custom_indicator_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/61_indicator_visualization_export_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/62_indicator_streaming_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/63_indicator_ws_bridge_demo.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/64_indicator_live_web.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/benchmark_utils.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/pb_mock.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/strategies/01_stock_dual_moving_average.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/strategies/02_stock_grid_trading.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/strategies/03_stock_atr_breakout.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/strategies/04_stock_momentum_rotation.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/strategies/05_stock_momentum_rotation_timer.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/strategies/06_stock_momentum_rotation_bucket.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/strategies/07_stock_momentum_rotation_on_timer.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/strategies/09_stock_momentum_rotation_after_bar.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/textbook/ch01_quickstart.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/textbook/ch02_programming.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/textbook/ch03_data.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/textbook/ch04_comparison.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/textbook/ch05_strategy.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/textbook/ch06_stock_a.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/textbook/ch07_futures.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/textbook/ch08_options.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/textbook/ch09_funds.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/textbook/ch10_analysis.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/textbook/ch11_optimization.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/textbook/ch12_ml.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/textbook/ch13_visualization.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/textbook/ch14_factor.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/textbook/ch15_live_trading.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/textbook/ch15_strategy_loader.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/examples/textbook/ch16_indicators.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/mkdocs.yml +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/analysis/__init__.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/analysis/benchmark.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/analyzer_plugin.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/backtest/__init__.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/backtest/__init__.pyi +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/backtest/result.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/checkpoint.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/config.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/data.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/factor/__init__.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/factor/engine.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/factor/ops.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/factor/parser.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/feed_adapter.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/fund/__init__.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/futures/__init__.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/gateway/base.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/gateway/broker_event_mapper.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/gateway/brokers/__init__.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/gateway/brokers/ctp/__init__.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/gateway/brokers/ctp/adapter.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/gateway/brokers/ctp/native.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/gateway/brokers/miniqmt/__init__.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/gateway/brokers/miniqmt/stub.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/gateway/brokers/ptrade/__init__.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/gateway/brokers/ptrade/stub.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/gateway/ctp_adapter.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/gateway/ctp_native.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/gateway/mapper.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/gateway/miniqmt.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/gateway/models.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/gateway/ptrade.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/gateway/registry.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/indicator.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/indicator_recording.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/indicator_stream.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/log.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/ml/__init__.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/ml/model.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/optimize.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/option/__init__.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/params.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/params_adapter.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/plot/__init__.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/plot/analysis.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/plot/dashboard.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/plot/indicator.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/plot/report.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/plot/strategy.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/plot/utils.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/py.typed +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/risk.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/sizer.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/stock/__init__.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/strategy_history.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/strategy_loader.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/strategy_logging.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/strategy_ml.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/strategy_order_events.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/strategy_position.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/strategy_scheduler.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/strategy_time.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/talib/__init__.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/talib/backend.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/talib/core.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/talib/funcs.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/utils/__init__.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/python/akquant/utils/inspector.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/requirements-dev.txt +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/scripts/cargo-test.sh +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/scripts/check_docs_api_examples.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/scripts/check_docs_links.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/scripts/dev-check.sh +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/scripts/find_legacy_execution_policy_calls.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/scripts/golden_baseline_report.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/account.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/analysis/mod.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/analysis/python.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/analysis/result.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/analysis/tests.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/analysis/tracker.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/analysis/types.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/bin/stub_gen.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/clock.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/context.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/data/aggregator.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/data/batch.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/data/client.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/data/feed.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/data/mod.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/engine/core.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/engine/mod.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/engine/python.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/engine/state.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/error.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/event.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/event_manager.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/execution/common.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/execution/crypto.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/execution/forex.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/execution/futures.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/execution/matcher.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/execution/mod.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/execution/option.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/execution/python.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/execution/realtime.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/execution/simulated.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/execution/slippage.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/execution/stock.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/history.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/indicators/momentum.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/indicators/momentum_oscillators.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/indicators/momentum_rates.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/indicators/moving_average.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/indicators/moving_average_compound.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/indicators/moving_average_core.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/indicators/moving_average_transforms.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/indicators/moving_average_windowed.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/indicators/trend.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/indicators/trend_directional.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/indicators/trend_oscillators.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/indicators/trend_regression.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/indicators/volatility.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/indicators/volatility_price.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/indicators/volatility_stats.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/indicators/volume.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/indicators.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/lib.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/log_context.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/margin/calculator.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/margin/engine.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/margin/mod.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/market/china.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/market/core.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/market/corporate_action.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/market/fund.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/market/futures.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/market/manager.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/market/mod.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/market/option.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/market/simple.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/market/stock.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/model/corporate_action.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/model/instrument.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/model/market_data.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/model/mod.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/model/order.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/model/timer.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/model/types.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/order_manager.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/pipeline/mod.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/pipeline/processor.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/pipeline/runner.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/pipeline/stages/channel.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/pipeline/stages/cleanup.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/pipeline/stages/data.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/pipeline/stages/execution.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/pipeline/stages/mod.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/pipeline/stages/statistics.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/pipeline/stages/strategy.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/portfolio.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/risk/common.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/risk/config.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/risk/futures.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/risk/manager.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/risk/mod.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/risk/option.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/risk/portfolio.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/risk/rule.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/risk/stock.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/settlement/expiry.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/settlement/handler.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/settlement/manager.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/settlement/mod.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/settlement/option.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/src/statistics/mod.rs +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/gateway_contract/test_recovery_contract.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/BASELINE_REPORT.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/LEGACY_EXECUTION_CALLS.md +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/baselines/futures_margin/equity_curve.parquet +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/baselines/futures_margin/metrics.json +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/baselines/futures_margin/orders.parquet +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/baselines/option_basic/equity_curve.parquet +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/baselines/option_basic/metrics.json +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/baselines/option_basic/orders.parquet +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/baselines/stock_t1/equity_curve.parquet +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/baselines/stock_t1/metrics.json +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/baselines/stock_t1/orders.parquet +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/baselines/stock_t1/trades.parquet +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/data/future_margin.parquet +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/data/future_margin.parquet.sha256 +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/data/option_basic.parquet +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/data/option_basic.parquet.sha256 +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/data/stock_t1.parquet +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/data/stock_t1.parquet.sha256 +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/gen_data.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/runner.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/strategies/futures_margin.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/strategies/option_basic.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/strategies/stock_t1.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/golden/test_golden.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_custom_matcher.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_data_catalog.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_docs_api_examples.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_docs_links.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_examples_regression.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_factor_engine.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_factor_ops.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_feed_adapter.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_gateway_brokers_paths.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_gateway_callbacks.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_gateway_ctp_adapter.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_gateway_ctp_native.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_gateway_factory.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_gateway_mapper.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_gateway_registry.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_indicator_live_web_example.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_indicator_recording.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_inspector.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_live_runner.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_orders_df.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_params_adapter.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_partial_filled_status.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_portfolio.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_quickstart_stream_consistency.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_report_helpers.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_report_plot_extensions.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_result_analysis_extensions.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_stop_orders.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_strategy_timers_indicators.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_t_plus_one.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_talib_backend.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_talib_compat.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_trades_df.py +0 -0
- {akquant-0.2.51 → akquant-0.3.2}/tests/test_version.py +0 -0
akquant-0.3.2/.gitignore
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# ── 构建产物 ──
|
|
2
|
+
target/
|
|
3
|
+
build/
|
|
4
|
+
dist/
|
|
5
|
+
site/
|
|
6
|
+
refs/
|
|
7
|
+
*.egg-info/
|
|
8
|
+
|
|
9
|
+
# ── Python ──
|
|
10
|
+
__pycache__/
|
|
11
|
+
*.so
|
|
12
|
+
*.dylib
|
|
13
|
+
*.dSYM/
|
|
14
|
+
*.pyd
|
|
15
|
+
*.pdb
|
|
16
|
+
|
|
17
|
+
# ── 环境 / 依赖 ──
|
|
18
|
+
.env
|
|
19
|
+
.venv
|
|
20
|
+
venv/
|
|
21
|
+
uv.lock
|
|
22
|
+
|
|
23
|
+
# ── IDE / 编辑器 ──
|
|
24
|
+
.idea/
|
|
25
|
+
.vscode/
|
|
26
|
+
.trae/
|
|
27
|
+
*.swp
|
|
28
|
+
|
|
29
|
+
# ── 操作系统 ──
|
|
30
|
+
.DS_Store
|
|
31
|
+
|
|
32
|
+
# ── 日志 ──
|
|
33
|
+
*.log
|
|
34
|
+
*.err
|
|
35
|
+
|
|
36
|
+
# ── 本地配置 ──
|
|
37
|
+
.cargo/config.toml
|
|
38
|
+
CLAUDE.md
|
|
39
|
+
|
|
40
|
+
# ── 本地数据 ──
|
|
41
|
+
/data_catalog/
|
|
42
|
+
|
|
43
|
+
# ── AI 工作流文档(内部,不公开)──
|
|
44
|
+
docs/superpowers
|
|
45
|
+
|
|
46
|
+
# ── 私有 broker 已拆分为独立包(akquant-qmf / akquant-middleware,独立私有仓)──
|
|
47
|
+
|
|
48
|
+
# ── 外部前置机/回测服务子项目(vendored,独立仓库,不纳入本仓版本管理)──
|
|
49
|
+
/vendor/
|
|
@@ -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`,将不会再被框架触发,请同步迁移到新名称。
|
|
@@ -30,7 +30,7 @@ dependencies = [
|
|
|
30
30
|
|
|
31
31
|
[[package]]
|
|
32
32
|
name = "akquant"
|
|
33
|
-
version = "0.2
|
|
33
|
+
version = "0.3.2"
|
|
34
34
|
dependencies = [
|
|
35
35
|
"anyhow",
|
|
36
36
|
"chrono",
|
|
@@ -692,9 +692,9 @@ dependencies = [
|
|
|
692
692
|
|
|
693
693
|
[[package]]
|
|
694
694
|
name = "ethnum"
|
|
695
|
-
version = "1.5.
|
|
695
|
+
version = "1.5.3"
|
|
696
696
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
697
|
-
checksum = "
|
|
697
|
+
checksum = "40404c3f5f511ec4da6fe866ddf6a717c309fdbb69fbbad7b0f3edab8f2e835f"
|
|
698
698
|
|
|
699
699
|
[[package]]
|
|
700
700
|
name = "event-listener"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: akquant
|
|
3
|
-
Version: 0.2
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Classifier: Programming Language :: Rust
|
|
5
5
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
6
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
@@ -222,8 +222,8 @@ min_margin_level 68.587671
|
|
|
222
222
|
|
|
223
223
|
AKQuant 提供了两组复杂订单助手,减少手写订单联动逻辑:
|
|
224
224
|
|
|
225
|
-
* `
|
|
226
|
-
* `
|
|
225
|
+
* `place_oco(first_order_id, second_order_id, group_id=None)`:将两个订单绑定为 OCO,任一成交后自动撤销另一单。
|
|
226
|
+
* `place_bracket(symbol, quantity, entry_price=None, stop_trigger_price=None, take_profit_price=None, ...)`:一次性提交 Bracket 结构;进场成交后自动挂出止损/止盈,并在双退出单场景下自动绑定 OCO。
|
|
227
227
|
|
|
228
228
|
```python
|
|
229
229
|
from akquant import OrderStatus, Strategy
|
|
@@ -236,7 +236,7 @@ class BracketHelperStrategy(Strategy):
|
|
|
236
236
|
if self.get_position(bar.symbol) > 0 or self.entry_order_id:
|
|
237
237
|
return
|
|
238
238
|
|
|
239
|
-
self.entry_order_id = self.
|
|
239
|
+
self.entry_order_id = self.place_bracket(
|
|
240
240
|
symbol=bar.symbol,
|
|
241
241
|
quantity=100,
|
|
242
242
|
stop_trigger_price=bar.close * 0.98,
|
|
@@ -167,8 +167,8 @@ min_margin_level 68.587671
|
|
|
167
167
|
|
|
168
168
|
AKQuant 提供了两组复杂订单助手,减少手写订单联动逻辑:
|
|
169
169
|
|
|
170
|
-
* `
|
|
171
|
-
* `
|
|
170
|
+
* `place_oco(first_order_id, second_order_id, group_id=None)`:将两个订单绑定为 OCO,任一成交后自动撤销另一单。
|
|
171
|
+
* `place_bracket(symbol, quantity, entry_price=None, stop_trigger_price=None, take_profit_price=None, ...)`:一次性提交 Bracket 结构;进场成交后自动挂出止损/止盈,并在双退出单场景下自动绑定 OCO。
|
|
172
172
|
|
|
173
173
|
```python
|
|
174
174
|
from akquant import OrderStatus, Strategy
|
|
@@ -181,7 +181,7 @@ class BracketHelperStrategy(Strategy):
|
|
|
181
181
|
if self.get_position(bar.symbol) > 0 or self.entry_order_id:
|
|
182
182
|
return
|
|
183
183
|
|
|
184
|
-
self.entry_order_id = self.
|
|
184
|
+
self.entry_order_id = self.place_bracket(
|
|
185
185
|
symbol=bar.symbol,
|
|
186
186
|
quantity=100,
|
|
187
187
|
stop_trigger_price=bar.close * 0.98,
|
|
@@ -45,7 +45,7 @@ def initialize(ctx):
|
|
|
45
45
|
ctx.sent = False
|
|
46
46
|
|
|
47
47
|
def on_bar(ctx, bar):
|
|
48
|
-
if not ctx.sent and
|
|
48
|
+
if not ctx.sent and getattr(ctx, "broker_ready", False):
|
|
49
49
|
ctx.submit_order(
|
|
50
50
|
symbol=bar.symbol,
|
|
51
51
|
side="Buy",
|
|
@@ -72,9 +72,11 @@ runner.run(duration="30s", show_progress=False)
|
|
|
72
72
|
|
|
73
73
|
## 4. Common troubleshooting
|
|
74
74
|
|
|
75
|
-
- `submit_order not
|
|
76
|
-
- Cause: trader gateway
|
|
77
|
-
- Fix: guard with `
|
|
75
|
+
- `submit_order` not ready yet
|
|
76
|
+
- Cause: the trader gateway has not finished connecting/logging in.
|
|
77
|
+
- Fix: guard with `if getattr(ctx, "broker_ready", False):` before placing
|
|
78
|
+
(readiness is decided by LiveRunner's heartbeat poll; submitting before
|
|
79
|
+
ready raises a clear error).
|
|
78
80
|
- `duplicate active client_order_id`
|
|
79
81
|
- Cause: reused active client id.
|
|
80
82
|
- Fix: generate a fresh `client_order_id` for each new order.
|
|
@@ -36,11 +36,11 @@ Your task is to write trading strategies or backtest scripts based on user requi
|
|
|
36
36
|
* `self.order_target_percent(target, symbol)`: Adjust position to target percentage.
|
|
37
37
|
* `self.order_target_value(target, symbol)`: Adjust position to target value.
|
|
38
38
|
* **Position**: `self.get_position(symbol)` returns current holding (float). `self.position.entry_price` or `self.ctx.get_position_entry_price(symbol)` returns runtime average entry price.
|
|
39
|
-
* **Account**: `self.ctx.cash`, `self.
|
|
39
|
+
* **Account**: `self.ctx.cash`, `self.equity`, `self.get_account()`.
|
|
40
40
|
|
|
41
41
|
4. **Indicators**:
|
|
42
42
|
* Prefer using `akquant.indicators` (e.g., `SMA`, `RSI`).
|
|
43
|
-
* Register in `__init__` or `on_start`: `self.sma = SMA(20); self.
|
|
43
|
+
* Register in `__init__` or `on_start`: `self.sma = SMA(20); self.register_precomputed_indicator("sma", self.sma)`.
|
|
44
44
|
* Access value via `self.sma.value`.
|
|
45
45
|
|
|
46
46
|
5. **Backtest Execution**:
|
|
@@ -94,7 +94,7 @@ def on_start(self):
|
|
|
94
94
|
else:
|
|
95
95
|
self.log("Resumed from snapshot. Indicators retained.")
|
|
96
96
|
|
|
97
|
-
self.
|
|
97
|
+
self.register_precomputed_indicator("sma", self.sma)
|
|
98
98
|
self.subscribe(self.symbol)
|
|
99
99
|
```
|
|
100
100
|
|
|
@@ -122,7 +122,7 @@ class MyStrategy(Strategy):
|
|
|
122
122
|
def on_start(self):
|
|
123
123
|
if not self.is_restored:
|
|
124
124
|
self.sma = SMA(10)
|
|
125
|
-
self.
|
|
125
|
+
self.register_precomputed_indicator("sma", self.sma)
|
|
126
126
|
|
|
127
127
|
# ... run phase 1 ...
|
|
128
128
|
save_snapshot(engine, strategy, "checkpoint.pkl")
|
|
@@ -479,7 +479,7 @@ The `examples/` directory contains more scripts demonstrating AKShare integratio
|
|
|
479
479
|
* Prints `bundle.metadata` to confirm the custom broker is resolved by factory.
|
|
480
480
|
|
|
481
481
|
* **[43_target_weights_rebalance.py](https://github.com/akfamily/akquant/blob/main/examples/43_target_weights_rebalance.py)**:
|
|
482
|
-
* Demonstrates TopN dynamic weights: rank symbols by momentum, select winners, then rebalance with `
|
|
482
|
+
* Demonstrates TopN dynamic weights: rank symbols by momentum, select winners, then rebalance with `rebalance_weights`.
|
|
483
483
|
* Shows practical usage of `liquidate_unmentioned` and `rebalance_tolerance`, then prints `selected_history` / `final_positions` / `final_equity`.
|
|
484
484
|
|
|
485
485
|
* **[46_broker_profile_demo.py](https://github.com/akfamily/akquant/blob/main/examples/46_broker_profile_demo.py)**:
|
|
@@ -81,7 +81,7 @@ Notes:
|
|
|
81
81
|
* `on_reject` is emitted once per order id when the order first becomes `Rejected`.
|
|
82
82
|
* `on_pre_open` is emitted once per trading day before the first regular bar/tick callback of that day.
|
|
83
83
|
* `on_before_trading` is emitted once per local trading date when the regular trading session starts; on the default backtest path this session is usually exposed as `Continuous`.
|
|
84
|
-
* `on_before_trading` / `on_daily_rebalance` always use a "previous trading day / previous snapshot only" visibility model; inside these callbacks, `get_history()`, `get_account()`, and `
|
|
84
|
+
* `on_before_trading` / `on_daily_rebalance` always use a "previous trading day / previous snapshot only" visibility model; inside these callbacks, `get_history()`, `get_account()`, and `equity` must not expose the current day's new bar or the current day's updated account view.
|
|
85
85
|
* `on_daily_rebalance_after_bar` runs after the framework has seen the first complete cross-symbol slice for the trading day; inside this callback, current-day history and the current account snapshot are visible.
|
|
86
86
|
* `on_after_trading` is emitted once per local trading date when leaving the regular trading session, or on the next event if day rollover occurs first.
|
|
87
87
|
* Inside `on_pre_open`, plain `buy/sell/order_target_*` calls automatically resolve to `price_basis=open, bar_offset=1, temporal=same_cycle` unless an explicit `fill_policy` is provided.
|
|
@@ -531,7 +531,7 @@ In AKQuant, order status transitions are as follows:
|
|
|
531
531
|
Converts to a market order when the market price touches the trigger price (`trigger_price`).
|
|
532
532
|
```python
|
|
533
533
|
# Stop Sell (Market) when price drops below 140
|
|
534
|
-
self.
|
|
534
|
+
self.sell(symbol="AAPL", quantity=100, trigger_price=140.0)
|
|
535
535
|
```
|
|
536
536
|
* **Target Orders**:
|
|
537
537
|
Automatically calculates buy/sell quantities to adjust the position to a target value.
|
|
@@ -544,7 +544,7 @@ In AKQuant, order status transitions are as follows:
|
|
|
544
544
|
```
|
|
545
545
|
Rebalance multiple symbols with a single target-weight call:
|
|
546
546
|
```python
|
|
547
|
-
self.
|
|
547
|
+
self.rebalance_weights(
|
|
548
548
|
target_weights={"AAPL": 0.4, "MSFT": 0.3, "GOOGL": 0.2},
|
|
549
549
|
liquidate_unmentioned=True,
|
|
550
550
|
rebalance_tolerance=0.01,
|
|
@@ -769,7 +769,7 @@ Notes:
|
|
|
769
769
|
|
|
770
770
|
- Opening a futures position does not deduct full notional from cash the way a spot buy does.
|
|
771
771
|
- For futures, use `equity` for net account value, `used_margin` for margin usage, and `notional_value` for leverage exposure.
|
|
772
|
-
- If you only need one "current total equity" number, prefer `
|
|
772
|
+
- If you only need one "current total equity" number, prefer `equity`, which is aligned with `get_account()["equity"]`.
|
|
773
773
|
|
|
774
774
|
## 6. Using High-Performance Indicators {: #indicatorset }
|
|
775
775
|
|
|
@@ -914,10 +914,10 @@ class IntradayStrategy(Strategy):
|
|
|
914
914
|
|
|
915
915
|
AKQuant provides helper APIs for linked order management:
|
|
916
916
|
|
|
917
|
-
* `self.
|
|
917
|
+
* `self.place_oco(first_order_id, second_order_id, group_id=None)`
|
|
918
918
|
* Binds two orders as OCO (One-Cancels-the-Other).
|
|
919
919
|
* Once either order is filled, the peer order is canceled automatically.
|
|
920
|
-
* `self.
|
|
920
|
+
* `self.place_bracket(symbol, quantity, entry_price=None, stop_trigger_price=None, take_profit_price=None, ...)`
|
|
921
921
|
* Submits a bracket structure in one call.
|
|
922
922
|
* After entry fill, stop-loss and take-profit exits are submitted automatically; when both exits exist, they are linked as OCO.
|
|
923
923
|
|
|
@@ -932,7 +932,7 @@ class BracketHelperStrategy(Strategy):
|
|
|
932
932
|
if self.get_position(bar.symbol) > 0 or self.entry_order_id:
|
|
933
933
|
return
|
|
934
934
|
|
|
935
|
-
self.entry_order_id = self.
|
|
935
|
+
self.entry_order_id = self.place_bracket(
|
|
936
936
|
symbol=bar.symbol,
|
|
937
937
|
quantity=100,
|
|
938
938
|
stop_trigger_price=bar.close * 0.98,
|
|
@@ -832,19 +832,20 @@ Note: if you do not pass an explicit `fill_policy` here, the framework defaults
|
|
|
832
832
|
* `self.position`: Position object for current symbol, with `size` and `available` properties.
|
|
833
833
|
* `self.now`: Current backtest time (`pd.Timestamp`).
|
|
834
834
|
* `self.runtime_config`: Runtime behavior config object (`StrategyRuntimeConfig`).
|
|
835
|
-
* `self.enable_precise_day_boundary_hooks`: Enable boundary timer based precise day hooks (default `False`). This switch changes trigger precision only; it does not change the visibility window of `get_history()`, `get_account()`, or `
|
|
835
|
+
* `self.enable_precise_day_boundary_hooks`: Enable boundary timer based precise day hooks (default `False`). This switch changes trigger precision only; it does not change the visibility window of `get_history()`, `get_account()`, or `equity` inside `on_before_trading` / `on_daily_rebalance`.
|
|
836
836
|
* `self.portfolio_update_eps`: Snapshot threshold; changes below it skip `on_portfolio_update` (default `0.0`).
|
|
837
837
|
* `self.error_mode`: Error handling mode, `"raise"` or `"continue"` (default `"raise"`).
|
|
838
838
|
* `self.re_raise_on_error`: Whether to re-raise user callback exception after `on_error` (default `True`).
|
|
839
839
|
|
|
840
840
|
**Trading Methods:**
|
|
841
841
|
|
|
842
|
-
* `buy(symbol, quantity, price=None, ...)`: Buy
|
|
843
|
-
*
|
|
842
|
+
* `buy(symbol, quantity, price=None, trigger_price=None, ...)`: Buy (open long / close short).
|
|
843
|
+
* Market order if `price` is not specified.
|
|
844
|
+
* Limit order if `price` is specified.
|
|
845
|
+
* Stop order (Stop Market) if `trigger_price` is specified.
|
|
846
|
+
* `sell(symbol, quantity, price=None, trigger_price=None, ...)`: Sell (close long / open short). Same parameters as above.
|
|
844
847
|
* `short(symbol, quantity, price=None, ...)`: Short sell.
|
|
845
848
|
* `cover(symbol, quantity, price=None, ...)`: Buy to cover.
|
|
846
|
-
* `stop_buy(symbol, trigger_price, quantity, ...)`: Stop buy (Stop Market). Triggers a market buy order when price breaks above `trigger_price`.
|
|
847
|
-
* `stop_sell(symbol, trigger_price, quantity, ...)`: Stop sell (Stop Market). Triggers a market sell order when price drops below `trigger_price`.
|
|
848
849
|
* `submit_order(..., order_type="StopTrail", trail_offset=..., trail_reference_price=None)`: Submit a trailing stop order. `trail_offset` must be greater than 0.
|
|
849
850
|
* `submit_order(..., order_type="StopTrailLimit", price=..., trail_offset=..., trail_reference_price=None)`: Submit a trailing stop-limit order. `price` and `trail_offset` are required.
|
|
850
851
|
* `submit_order(..., broker_options={...})`: Optional broker extension fields passthrough (backtest currently records them on `order.broker_options` for debugging/audit).
|
|
@@ -852,7 +853,7 @@ Note: if you do not pass an explicit `fill_policy` here, the framework defaults
|
|
|
852
853
|
* `place_trailing_stop_limit(symbol, quantity, price, trail_offset, side="Sell", trail_reference_price=None, ...) -> str`: Helper for trailing stop-limit orders, promoted to limit order when triggered.
|
|
853
854
|
* `order_target_value(target_value, symbol, price=None)`: Adjust position to target value.
|
|
854
855
|
* `order_target_percent(target_percent, symbol, price=None)`: Adjust position to target account percentage.
|
|
855
|
-
* `
|
|
856
|
+
* `rebalance_weights(target_weights, price_map=None, liquidate_unmentioned=False, allow_leverage=False, rebalance_tolerance=0.0, ...)`: Rebalance a multi-asset portfolio by target weights.
|
|
856
857
|
* `target_weights` is `{symbol: weight}` and by default requires total weight `<= 1.0`.
|
|
857
858
|
* `liquidate_unmentioned=True` sets all existing non-mentioned positions to target `0`.
|
|
858
859
|
* Orders are submitted in sell-first then buy-second order to reduce cash-lock conflicts.
|
|
@@ -860,8 +861,8 @@ Note: if you do not pass an explicit `fill_policy` here, the framework defaults
|
|
|
860
861
|
* `close_position(symbol)`: Close position for a specific instrument.
|
|
861
862
|
* `cancel_order(order_id: str)`: Cancel a specific order.
|
|
862
863
|
* `cancel_all_orders(symbol)`: Cancel all pending orders for a specific instrument. If `symbol` is omitted, cancels all orders.
|
|
863
|
-
* `
|
|
864
|
-
* `
|
|
864
|
+
* `place_oco(first_order_id, second_order_id, group_id=None) -> str`: Create an OCO order group. Once one order is filled, the peer order is canceled automatically.
|
|
865
|
+
* `place_bracket(symbol, quantity, entry_price=None, stop_trigger_price=None, take_profit_price=None, ...) -> str`: Create a bracket order. The entry order is submitted first, then stop-loss/take-profit exits are submitted after entry fill; if both exits exist, they are linked as OCO automatically.
|
|
865
866
|
|
|
866
867
|
**Data & Utilities:**
|
|
867
868
|
|
|
@@ -869,17 +870,17 @@ Note: if you do not pass an explicit `fill_policy` here, the framework defaults
|
|
|
869
870
|
* `get_history_df(count, symbol) -> pd.DataFrame`: Get history data DataFrame (OHLCV).
|
|
870
871
|
* `get_position(symbol) -> float`: Get current position size. This still returns a numeric quantity, not an object.
|
|
871
872
|
* `get_available_position(symbol) -> float`: Get available position size.
|
|
872
|
-
* `
|
|
873
|
+
* `positions -> Dict[str, float]`: Get all positions by symbol (read-only property).
|
|
873
874
|
* `self.position.entry_price -> float`: Get the current symbol's average entry price via the `Position` helper.
|
|
874
875
|
* `self.position.avg_price -> float`: Alias of `entry_price`.
|
|
875
876
|
* `ctx.get_position_entry_price(symbol) -> float`: Get the current average entry price for one symbol.
|
|
876
877
|
* `ctx.get_position_entry_prices() -> Dict[str, float]`: Get current average entry prices for all symbols.
|
|
877
|
-
* `
|
|
878
|
+
* `cash -> float`: Get current available cash (read-only property).
|
|
878
879
|
* `get_account() -> Dict[str, float]`: Get an account snapshot. Common fields include `cash`, `equity`, `market_value`, `notional_value`, `frozen_cash`, `margin`, `used_margin`, `free_margin`, `unrealized_pnl`, `borrowed_cash`, `short_market_value`, `maintenance_ratio`, `account_mode`, `accrued_interest`, and `daily_interest`.
|
|
879
880
|
* In cash / spot-style accounts, `market_value` usually represents marked position value.
|
|
880
881
|
* In futures margin accounts, `equity` is account equity, `used_margin` is margin in use, `notional_value` is futures notional exposure, and `unrealized_pnl` is marked floating PnL. Futures trades do not deduct full notional from `cash` the way spot buys do, and notional exposure is not mirrored into `market_value` as if it were spot inventory.
|
|
881
882
|
* `cash` is the cash balance; `free_margin` (= `equity - used_margin`) is the amount actually available to open new positions and matches the `Available` value shown in the rejection log when an order is rejected. In futures margin accounts, opening a position does not deduct margin from `cash`, so `cash` is usually larger than `free_margin`; in stock cash accounts the two are equal.
|
|
882
|
-
* Inside strategy callbacks, prefer `
|
|
883
|
+
* Inside strategy callbacks, prefer `equity` when you only need current total equity; it is aligned with `get_account()["equity"]`.
|
|
883
884
|
* `get_order(order_id) -> Order`: Get details of a specific order.
|
|
884
885
|
* `get_open_orders(symbol) -> List[Order]`: Get list of open orders.
|
|
885
886
|
* `subscribe(instrument_id: str)`: Subscribe to market data. Must be called explicitly for multi-asset backtesting or live trading to receive `on_tick`/`on_bar` callbacks.
|
|
@@ -367,7 +367,7 @@ result = run_backtest(data=df, strategy=MetaQuickStrategy, config=config)
|
|
|
367
367
|
|
|
368
368
|
## Complex Orders in 30 Seconds
|
|
369
369
|
|
|
370
|
-
If you need an entry + stop-loss + take-profit flow with automatic OCO linkage, use `
|
|
370
|
+
If you need an entry + stop-loss + take-profit flow with automatic OCO linkage, use `place_bracket` directly:
|
|
371
371
|
|
|
372
372
|
```python
|
|
373
373
|
from akquant import OrderStatus, Strategy
|
|
@@ -379,7 +379,7 @@ class BracketQuickStrategy(Strategy):
|
|
|
379
379
|
def on_bar(self, bar):
|
|
380
380
|
if self.get_position(bar.symbol) > 0 or self.entry_order_id:
|
|
381
381
|
return
|
|
382
|
-
self.entry_order_id = self.
|
|
382
|
+
self.entry_order_id = self.place_bracket(
|
|
383
383
|
symbol=bar.symbol,
|
|
384
384
|
quantity=100,
|
|
385
385
|
stop_trigger_price=bar.close * 0.98,
|
|
@@ -51,11 +51,11 @@ Low-level Engine API naming:
|
|
|
51
51
|
## Futures Margin Account Snapshot Semantics
|
|
52
52
|
|
|
53
53
|
Under AKQuant's futures margin-account semantics, read `get_account()` and
|
|
54
|
-
`
|
|
54
|
+
`equity` like this:
|
|
55
55
|
|
|
56
56
|
- `cash`: cash balance. Opening a futures position does not deduct full notional
|
|
57
57
|
the way a spot buy does; cash mainly reflects fees and realized cash flows.
|
|
58
|
-
- `equity`: account equity.
|
|
58
|
+
- `equity`: account equity. This is the `equity` property.
|
|
59
59
|
- `used_margin` / `margin`: margin currently in use.
|
|
60
60
|
- `free_margin`: available margin (`equity - used_margin`), i.e. the amount
|
|
61
61
|
actually usable to open new positions. When an order is rejected for
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# 如何新增一个 Broker
|
|
2
|
+
|
|
3
|
+
本页说明 akquant broker 网关层的插件契约:新增一个 broker 需要实现哪些接口、
|
|
4
|
+
声明哪些能力、以及如何把下单请求路由到具体柜台。目标是让接入者不修改
|
|
5
|
+
`akquant.gateway` 核心代码即可插入一个新的交易通道。
|
|
6
|
+
|
|
7
|
+
如果只是想在不改内置工厂分支的前提下注册一个 broker,先看
|
|
8
|
+
[自定义 Broker 注册](custom_broker_registry.md);本页补充的是"网关本身怎么写"。
|
|
9
|
+
|
|
10
|
+
## 总览:五步契约
|
|
11
|
+
|
|
12
|
+
1. 写 **builder** 函数,通过 `register_broker(name, builder)` 注册(或者内置
|
|
13
|
+
broker 直接放进 `python/akquant/gateway/brokers/builtins.py`,由
|
|
14
|
+
`register_builtin_brokers()` 统一注册)。
|
|
15
|
+
2. 声明 **`BrokerCapability`**:`broker_extra_fields` 列出本 broker 允许的
|
|
16
|
+
订单专属字段,`features` 声明任意能力标志。
|
|
17
|
+
3. 继承 **`TraderGatewayBase`** 实现必需方法。
|
|
18
|
+
4. 在 `place_order` 里按 `req.asset_type` 路由品种、从 `req.extra` 取专属
|
|
19
|
+
字段,并维护 broker 订单号与 `client_order_id` 的映射。
|
|
20
|
+
5. 纯交易 broker(不接行情)令 `GatewayBundle(market_gateway=None, ...)`,
|
|
21
|
+
行情继续走 akquant 现有 `DataFeed`。
|
|
22
|
+
|
|
23
|
+
## 1. Builder:注册入口
|
|
24
|
+
|
|
25
|
+
Builder 是一个可调用对象,签名固定为:
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
def builder(
|
|
29
|
+
feed: DataFeed,
|
|
30
|
+
symbols: Sequence[str],
|
|
31
|
+
use_aggregator: bool,
|
|
32
|
+
**kwargs: Any,
|
|
33
|
+
) -> GatewayBundle:
|
|
34
|
+
...
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
- 第三方/内部 broker:调用 `register_broker(name, builder)`(来自
|
|
38
|
+
`akquant.gateway`),注册后 `create_gateway_bundle(broker=name, ...)` 会
|
|
39
|
+
优先解析到它。
|
|
40
|
+
- 想合并进内置分支的 broker:把 builder 函数加进
|
|
41
|
+
`python/akquant/gateway/brokers/builtins.py`,并在
|
|
42
|
+
`register_builtin_brokers()` 里追加一行 `register_broker("xxx", _build_xxx)`。
|
|
43
|
+
|
|
44
|
+
Builder 内部通常做三件事:校验必填 `kwargs`、构造 `TraderGateway`(以及可选的
|
|
45
|
+
`MarketGateway`)、把 `trader_gateway.get_capabilities()` 的结果写入
|
|
46
|
+
`GatewayBundle.trader_capabilities`,供上层校验 `extra` 字段用。
|
|
47
|
+
|
|
48
|
+
## 2. 声明 `BrokerCapability`
|
|
49
|
+
|
|
50
|
+
`BrokerCapability`(`from akquant.gateway.broker_models import BrokerCapability`)
|
|
51
|
+
是一个 frozen dataclass,描述这个 broker 的执行语义边界:
|
|
52
|
+
|
|
53
|
+
- `broker_extra_fields: tuple[str, ...]`:策略下单时通过
|
|
54
|
+
`submit_order(..., extra={...})` 传入的柜台专属字段,必须在这里声明;
|
|
55
|
+
未声明的 key 会在校验时被拒绝(`validate_broker_extra` 会抛
|
|
56
|
+
`RuntimeError`,列出未声明字段与已声明集合)。
|
|
57
|
+
- `features: frozenset[str]`:任意能力标志的开放集合,用于策略侧按需探测
|
|
58
|
+
"这个 broker 支不支持某个特性",不做强类型约束。
|
|
59
|
+
- 其余字段(`position_effect`、`reduce_only`、`supports_short_sell`、
|
|
60
|
+
`supported_position_effects` 等)描述开平仓/做空等语义是否可用,按 broker
|
|
61
|
+
实际能力如实填写即可,不确定的保持默认值(保守)。
|
|
62
|
+
|
|
63
|
+
`TraderGateway` 协议要求实现 `get_capabilities() -> BrokerCapability`,
|
|
64
|
+
通常返回一个模块级的 `default_capability()` 单例:
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
def default_capability() -> BrokerCapability:
|
|
68
|
+
return BrokerCapability(
|
|
69
|
+
broker_name="mybroker",
|
|
70
|
+
broker_extra_fields=("account_id", "order_style"),
|
|
71
|
+
features=frozenset({"supports_stop_limit"}),
|
|
72
|
+
)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 3. 继承 `TraderGatewayBase`
|
|
76
|
+
|
|
77
|
+
`from akquant.gateway.trader_base import TraderGatewayBase` 提供了所有
|
|
78
|
+
broker 共享的管件:回调注册、id 反查表、以及默认的
|
|
79
|
+
`heartbeat`/`sync_open_orders`/`sync_today_trades` 实现。子类只需要实现
|
|
80
|
+
`TraderGateway` 协议中还缺的部分:
|
|
81
|
+
|
|
82
|
+
必须实现:
|
|
83
|
+
|
|
84
|
+
- `connect()` / `disconnect()` / `start()` —— 生命周期
|
|
85
|
+
- `place_order(req) -> str` / `cancel_order(broker_order_id)`
|
|
86
|
+
- `query_order(broker_order_id)` / `query_trades(since=None)`
|
|
87
|
+
- `query_account()` / `query_positions()`
|
|
88
|
+
- `get_capabilities() -> BrokerCapability`
|
|
89
|
+
|
|
90
|
+
基类已提供、通常不需要重写:
|
|
91
|
+
|
|
92
|
+
- 回调注册:`on_order` / `on_trade` / `on_execution_report`
|
|
93
|
+
- id 反查:`record_broker_order(broker_order_id, client_order_id)` /
|
|
94
|
+
`client_order_id_for(broker_order_id)`
|
|
95
|
+
- 分发:`_emit_order` / `_emit_trade` / `_emit_exec_from_order`
|
|
96
|
+
- 默认实现:`heartbeat()`(恒真)、`sync_open_orders()` /
|
|
97
|
+
`sync_today_trades()`(空列表)—— 如果 broker 支持断线补齐,覆盖这两个
|
|
98
|
+
方法即可。
|
|
99
|
+
|
|
100
|
+
## 4. `place_order` 里的路由与 id 映射
|
|
101
|
+
|
|
102
|
+
`UnifiedOrderRequest` 里的 `asset_type` 用来在 `place_order` 内部路由到不同
|
|
103
|
+
品种的下单通道(例如证券 vs 期货);`extra: dict[str, Any]` 携带的是
|
|
104
|
+
`BrokerCapability.broker_extra_fields` 里声明过的柜台专属字段,直接从
|
|
105
|
+
`req.extra` 取值即可(上层已按声明集合校验过,未声明的 key 不会出现)。
|
|
106
|
+
|
|
107
|
+
下单成功后,用 `self.record_broker_order(broker_order_id, req.client_order_id)`
|
|
108
|
+
记录柜台委托号到策略 `client_order_id` 的映射;收到委托/成交回报时,用
|
|
109
|
+
`self.client_order_id_for(broker_order_id)` 反查回 `client_order_id`,再拼成
|
|
110
|
+
统一模型对象经 `self._emit_order(...)` / `self._emit_trade(...)` /
|
|
111
|
+
`self._emit_exec_from_order(...)` 分发给策略层回调。
|
|
112
|
+
|
|
113
|
+
## 5. 纯交易 broker:行情走现有 feed
|
|
114
|
+
|
|
115
|
+
如果新 broker 只做交易、不提供行情(多数国内前置机/柜台都是这种情况),
|
|
116
|
+
builder 返回的 `GatewayBundle` 里 `market_gateway=None` 即可,行情继续由
|
|
117
|
+
akquant 现有的 `DataFeed` 提供:
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
return GatewayBundle(
|
|
121
|
+
market_gateway=None,
|
|
122
|
+
trader_gateway=trader_gateway,
|
|
123
|
+
trader_capabilities=trader_gateway.get_capabilities(),
|
|
124
|
+
metadata={"broker": "mybroker"},
|
|
125
|
+
)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## 最小骨架
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
from __future__ import annotations
|
|
132
|
+
|
|
133
|
+
from typing import Any, Sequence
|
|
134
|
+
|
|
135
|
+
from akquant import DataFeed
|
|
136
|
+
from akquant.gateway import register_broker
|
|
137
|
+
from akquant.gateway.broker_models import (
|
|
138
|
+
BrokerCapability,
|
|
139
|
+
UnifiedAccount,
|
|
140
|
+
UnifiedOrderRequest,
|
|
141
|
+
UnifiedOrderSnapshot,
|
|
142
|
+
UnifiedPosition,
|
|
143
|
+
UnifiedTrade,
|
|
144
|
+
)
|
|
145
|
+
from akquant.gateway.protocols import GatewayBundle
|
|
146
|
+
from akquant.gateway.trader_base import TraderGatewayBase
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def default_capability() -> BrokerCapability:
|
|
150
|
+
return BrokerCapability(
|
|
151
|
+
broker_name="mybroker",
|
|
152
|
+
broker_extra_fields=("account_id",),
|
|
153
|
+
features=frozenset(),
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class MyTraderGateway(TraderGatewayBase):
|
|
158
|
+
"""最小可运行的 TraderGateway 骨架。"""
|
|
159
|
+
|
|
160
|
+
def __init__(self, capability: BrokerCapability | None = None) -> None:
|
|
161
|
+
super().__init__()
|
|
162
|
+
self._capability = capability or default_capability()
|
|
163
|
+
|
|
164
|
+
def connect(self) -> None:
|
|
165
|
+
... # 登录/建立会话
|
|
166
|
+
|
|
167
|
+
def disconnect(self) -> None:
|
|
168
|
+
... # 释放连接
|
|
169
|
+
|
|
170
|
+
def start(self) -> None:
|
|
171
|
+
... # 建立推送长连、开始分发回报
|
|
172
|
+
|
|
173
|
+
def get_capabilities(self) -> BrokerCapability:
|
|
174
|
+
return self._capability
|
|
175
|
+
|
|
176
|
+
def place_order(self, req: UnifiedOrderRequest) -> str:
|
|
177
|
+
# 按 req.asset_type 路由品种;req.extra 取柜台专属字段。
|
|
178
|
+
account_id = req.extra.get("account_id")
|
|
179
|
+
broker_order_id = self._send_order_to_broker(req, account_id)
|
|
180
|
+
if broker_order_id:
|
|
181
|
+
self.record_broker_order(broker_order_id, req.client_order_id)
|
|
182
|
+
return broker_order_id
|
|
183
|
+
|
|
184
|
+
def cancel_order(self, broker_order_id: str) -> None:
|
|
185
|
+
... # 调用柜台撤单接口
|
|
186
|
+
|
|
187
|
+
def query_order(self, broker_order_id: str) -> UnifiedOrderSnapshot | None:
|
|
188
|
+
... # 查询单笔委托并转换为 UnifiedOrderSnapshot
|
|
189
|
+
|
|
190
|
+
def query_trades(self, since: int | None = None) -> list[UnifiedTrade]:
|
|
191
|
+
... # 查询成交并转换为 UnifiedTrade 列表
|
|
192
|
+
|
|
193
|
+
def query_account(self) -> UnifiedAccount | None:
|
|
194
|
+
... # 查询资金账户
|
|
195
|
+
|
|
196
|
+
def query_positions(self) -> list[UnifiedPosition]:
|
|
197
|
+
... # 查询持仓
|
|
198
|
+
|
|
199
|
+
def _on_broker_push(self, event: str, data: dict[str, Any]) -> None:
|
|
200
|
+
# 收到推送后:反查 client_order_id,再分发给策略层回调。
|
|
201
|
+
broker_order_id = str(data.get("order_id", ""))
|
|
202
|
+
client_order_id = self.client_order_id_for(broker_order_id)
|
|
203
|
+
if event == "order_update":
|
|
204
|
+
snapshot = self._parse_order(data, client_order_id)
|
|
205
|
+
self._emit_order(snapshot)
|
|
206
|
+
self._emit_exec_from_order(snapshot)
|
|
207
|
+
elif event == "trade_update":
|
|
208
|
+
self._emit_trade(self._parse_trade(data, client_order_id))
|
|
209
|
+
|
|
210
|
+
def _send_order_to_broker(
|
|
211
|
+
self, req: UnifiedOrderRequest, account_id: Any
|
|
212
|
+
) -> str:
|
|
213
|
+
raise NotImplementedError
|
|
214
|
+
|
|
215
|
+
def _parse_order(
|
|
216
|
+
self, data: dict[str, Any], client_order_id: str
|
|
217
|
+
) -> UnifiedOrderSnapshot:
|
|
218
|
+
raise NotImplementedError
|
|
219
|
+
|
|
220
|
+
def _parse_trade(self, data: dict[str, Any], client_order_id: str) -> UnifiedTrade:
|
|
221
|
+
raise NotImplementedError
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def build_mybroker(
|
|
225
|
+
feed: DataFeed, symbols: Sequence[str], use_aggregator: bool, **kwargs: Any
|
|
226
|
+
) -> GatewayBundle:
|
|
227
|
+
_ = (feed, symbols, use_aggregator)
|
|
228
|
+
trader_gateway = MyTraderGateway()
|
|
229
|
+
return GatewayBundle(
|
|
230
|
+
market_gateway=None, # 纯交易 broker:行情走 akquant 现有 feed
|
|
231
|
+
trader_gateway=trader_gateway,
|
|
232
|
+
trader_capabilities=trader_gateway.get_capabilities(),
|
|
233
|
+
metadata={"broker": "mybroker"},
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
register_broker("mybroker", build_mybroker)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## 参考实现与相关文档
|
|
241
|
+
|
|
242
|
+
- [自定义 Broker 注册](custom_broker_registry.md) —— `register_broker` /
|
|
243
|
+
`create_gateway_bundle` 等注册 API 的详细说明。
|
|
244
|
+
- [Broker Capability Matrix](broker_capability_matrix.md) —— 各内置 broker
|
|
245
|
+
的能力矩阵与统一错误规范,声明 `BrokerCapability` 前建议先对照。
|
|
@@ -45,7 +45,7 @@ def initialize(ctx):
|
|
|
45
45
|
ctx.sent = False
|
|
46
46
|
|
|
47
47
|
def on_bar(ctx, bar):
|
|
48
|
-
if not ctx.sent and
|
|
48
|
+
if not ctx.sent and getattr(ctx, "broker_ready", False):
|
|
49
49
|
ctx.submit_order(
|
|
50
50
|
symbol=bar.symbol,
|
|
51
51
|
side="Buy",
|
|
@@ -72,9 +72,10 @@ runner.run(duration="30s", show_progress=False)
|
|
|
72
72
|
|
|
73
73
|
## 4. 常见排查
|
|
74
74
|
|
|
75
|
-
- `submit_order
|
|
76
|
-
-
|
|
77
|
-
- 处理:在 `on_bar`
|
|
75
|
+
- `submit_order` 尚未就绪
|
|
76
|
+
- 原因:交易网关尚未完成连接/登录。
|
|
77
|
+
- 处理:在 `on_bar` 中用 `if getattr(ctx, "broker_ready", False):` 门首单
|
|
78
|
+
(broker 就绪由 LiveRunner 的 heartbeat 轮询裁定;就绪前调用会抛清晰错误)。
|
|
78
79
|
- `duplicate active client_order_id`
|
|
79
80
|
- 原因:重复提交活跃 client id。
|
|
80
81
|
- 处理:每次下单生成新的 `client_order_id`。
|