akquant 0.2.30__tar.gz → 0.2.32__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.2.30 → akquant-0.2.32}/Cargo.lock +1 -1
- {akquant-0.2.30 → akquant-0.2.32}/Cargo.toml +1 -1
- {akquant-0.2.30 → akquant-0.2.32}/PKG-INFO +1 -1
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/guide/strategy.md +6 -5
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/reference/api.md +4 -3
- akquant-0.2.32/docs/javascripts/search-lang-filter.js +142 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/guide/strategy.md +4 -3
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/reference/api.md +4 -4
- {akquant-0.2.30 → akquant-0.2.32}/mkdocs.yml +1 -4
- {akquant-0.2.30 → akquant-0.2.32}/pyproject.toml +1 -1
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/strategy.py +10 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/strategy_events.py +9 -7
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/strategy_framework_hooks.py +141 -38
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/strategy_history.py +13 -2
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/strategy_order_events.py +6 -1
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/strategy_trading_api.py +58 -22
- {akquant-0.2.30 → akquant-0.2.32}/src/context.rs +82 -2
- {akquant-0.2.30 → akquant-0.2.32}/src/engine/core.rs +68 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/history.rs +16 -1
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/current/futures_margin/metrics.json +1 -1
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/current/futures_margin/orders.parquet +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/current/option_basic/metrics.json +1 -1
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/current/option_basic/orders.parquet +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/current/stock_t1/metrics.json +1 -1
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/current/stock_t1/orders.parquet +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_strategy_extras.py +303 -1
- {akquant-0.2.30 → akquant-0.2.32}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/.github/workflows/deploy-docs.yml +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/.github/workflows/docs-quality.yml +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/.github/workflows/release.yml +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/.gitignore +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/.pre-commit-config.yaml +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/CHANGELOG.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/CODE_OF_CONDUCT.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/CONTRIBUTING.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/LICENSE +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/README.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/assets/dashboard_preview.png +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/assets/logo.svg +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/assets/social_preview.png +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/CNAME +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/assets/akquant-icon.svg +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/assets/akquant-logo.svg +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/assets/reports/akquant_report.html +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/advanced/analyzer_plugin_spec.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/advanced/broker_capability_matrix.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/advanced/custom_broker_production_checklist.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/advanced/custom_broker_registry.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/advanced/data_feed_adapter_spec.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/advanced/live_functional_quickstart.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/advanced/llm.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/advanced/ml.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/advanced/multi_strategy_guide.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/advanced/multi_timeframe_feed_api.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/advanced/runtime_config.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/advanced/strategy_style_decision.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/advanced/timezone.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/advanced/warm_start.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/guide/analysis.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/guide/cross_section_checklist.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/guide/custom_indicator.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/guide/data.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/guide/examples.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/guide/factor.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/guide/indicator_scenario_quickref.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/guide/optimization.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/guide/python_basics.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/guide/quant_basics.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/guide/rust_indicator_reference.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/guide/talib_indicator_playbook.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/guide/testing.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/guide/visualization.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/index.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/meta/architecture.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/meta/internals.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/start/first_strategy.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/start/installation.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/start/quickstart.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/start/setup_guide.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/textbook/01_foundations.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/textbook/02_programming.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/textbook/03_data.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/textbook/04_backtest_engine.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/textbook/05_strategy.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/textbook/06_stock_a.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/textbook/07_futures.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/textbook/08_options.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/textbook/09_funds.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/textbook/10_analysis.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/textbook/11_optimization.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/textbook/12_ml.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/textbook/13_visualization.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/textbook/14_factor.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/textbook/15_live_trading.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/textbook/16_rust_indicators.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/en/textbook/index.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/javascripts/mathjax.js +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/robots.txt +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/advanced/analyzer_plugin_spec.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/advanced/broker_capability_matrix.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/advanced/custom_broker_production_checklist.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/advanced/custom_broker_registry.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/advanced/data_feed_adapter_spec.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/advanced/live_functional_quickstart.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/advanced/llm.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/advanced/ml.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/advanced/multi_strategy_guide.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/advanced/multi_timeframe_feed_api.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/advanced/runtime_config.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/advanced/strategy_style_decision.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/advanced/timezone.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/advanced/warm_start.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/guide/analysis.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/guide/cross_section_checklist.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/guide/custom_indicator.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/guide/data.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/guide/examples.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/guide/factor.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/guide/indicator_scenario_quickref.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/guide/optimization.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/guide/python_basics.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/guide/quant_basics.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/guide/rust_indicator_reference.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/guide/talib_indicator_playbook.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/guide/testing.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/guide/visualization.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/index.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/meta/architecture.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/meta/internals.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/start/first_strategy.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/start/installation.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/start/quickstart.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/start/setup_guide.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/textbook/01_foundations.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/textbook/02_programming.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/textbook/03_data.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/textbook/04_backtest_engine.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/textbook/05_strategy.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/textbook/06_stock_a.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/textbook/07_futures.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/textbook/08_options.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/textbook/09_funds.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/textbook/10_analysis.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/textbook/11_optimization.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/textbook/12_ml.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/textbook/13_visualization.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/textbook/14_factor.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/textbook/15_live_trading.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/textbook/16_rust_indicators.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/docs/zh/textbook/index.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/01_quickstart.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/02_parameter_optimization.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/03_parameter_optimization_advanced.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/04_mixed_assets.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/05_live_trading_ctp.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/06_complex_orders.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/07_option_test.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/08_event_callbacks.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/09_ml_framework.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/10_ml_walk_forward.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/11_plot_visualization.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/12_wfo_integrated.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/13_quantstats_report.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/14_multi_frequency.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/15_plot_intraday.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/16_adj_returns_signal.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/17_readme_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/18_benchmark_multisymbol.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/19_factor_expression.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/20_risk_management_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/21_warm_start_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/22_strategy_runtime_config_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/23_functional_callbacks_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/24_functional_tick_simulation_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/25_streaming_backtest_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/26_streaming_quickstart.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/27_streaming_monitoring_console.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/28_streaming_alerts_and_persist.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/29_streaming_event_report.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/30_streaming_report_oneclick.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/31_streaming_live_console.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/32_streaming_live_web.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/33_report_and_analysis_outputs.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/34_multi_strategy_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/35_custom_broker_registry_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/36_trailing_orders.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/37_feed_replay_alignment_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/38_live_functional_strategy_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/39_live_broker_submit_order_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/40_functional_multi_slot_risk_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/41_live_multi_slot_orchestration_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/42_live_broker_event_audit_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/43_target_weights_rebalance.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/44_strategy_source_loader_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/45_talib_indicator_playbook_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/46_broker_profile_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/47_margin_liquidation_audit_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/48_margin_liquidation_priority_compare.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/49_on_expiry_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/50_framework_hooks_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/51_class_tick_callbacks_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/52_pre_open_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/53_timer_to_pre_open_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/54_functional_pre_open_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/55_functional_ml_walk_forward.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/56_functional_warm_start_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/57_functional_multi_slot_warm_start_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/58_incremental_bootstrap_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/59_akshare_etf_rotation.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/60_custom_indicator_demo.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/README.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/benchmark_utils.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/pb_mock.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/strategies/01_stock_dual_moving_average.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/strategies/02_stock_grid_trading.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/strategies/03_stock_atr_breakout.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/strategies/04_stock_momentum_rotation.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/strategies/05_stock_momentum_rotation_timer.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/strategies/06_stock_momentum_rotation_bucket.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/strategies/07_stock_momentum_rotation_on_timer.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/strategies/08_target_positions_long_short.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/strategies/README.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/textbook/ch01_quickstart.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/textbook/ch02_programming.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/textbook/ch03_data.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/textbook/ch04_comparison.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/textbook/ch05_strategy.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/textbook/ch06_stock_a.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/textbook/ch07_futures.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/textbook/ch08_options.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/textbook/ch09_funds.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/textbook/ch09_portfolio.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/textbook/ch10_analysis.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/textbook/ch11_optimization.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/textbook/ch12_ml.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/textbook/ch13_visualization.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/textbook/ch14_factor.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/textbook/ch15_live_trading.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/examples/textbook/ch15_strategy_loader.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/__init__.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/akquant.pyi +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/analyzer_plugin.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/backtest/__init__.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/backtest/__init__.pyi +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/backtest/engine.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/backtest/result.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/checkpoint.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/config.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/data.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/factor/__init__.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/factor/engine.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/factor/ops.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/factor/parser.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/feed_adapter.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/fund/__init__.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/futures/__init__.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/gateway/__init__.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/gateway/base.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/gateway/ctp_adapter.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/gateway/ctp_native.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/gateway/factory.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/gateway/mapper.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/gateway/miniqmt.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/gateway/models.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/gateway/ptrade.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/gateway/registry.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/indicator.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/live.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/log.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/ml/__init__.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/ml/model.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/optimize.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/option/__init__.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/params.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/params_adapter.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/plot/__init__.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/plot/analysis.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/plot/dashboard.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/plot/report.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/plot/strategy.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/plot/utils.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/py.typed +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/risk.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/sizer.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/stock/__init__.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/strategy_loader.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/strategy_logging.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/strategy_ml.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/strategy_position.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/strategy_scheduler.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/strategy_time.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/talib/__init__.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/talib/backend.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/talib/core.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/talib/funcs.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/utils/__init__.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/python/akquant/utils/inspector.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/requirements-dev.txt +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/scripts/cargo-test.sh +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/scripts/check_docs_api_examples.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/scripts/check_docs_links.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/scripts/dev-check.sh +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/scripts/find_legacy_execution_policy_calls.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/scripts/golden_baseline_report.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/account.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/analysis/mod.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/analysis/python.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/analysis/result.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/analysis/tests.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/analysis/tracker.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/analysis/types.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/bin/stub_gen.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/clock.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/data/aggregator.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/data/batch.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/data/client.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/data/feed.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/data/mod.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/engine/mod.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/engine/python.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/engine/state.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/error.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/event.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/event_manager.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/execution/common.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/execution/crypto.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/execution/forex.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/execution/futures.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/execution/matcher.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/execution/mod.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/execution/option.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/execution/python.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/execution/realtime.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/execution/simulated.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/execution/slippage.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/execution/stock.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/indicators/momentum.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/indicators/momentum_oscillators.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/indicators/momentum_rates.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/indicators/moving_average.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/indicators/moving_average_compound.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/indicators/moving_average_core.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/indicators/moving_average_transforms.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/indicators/moving_average_windowed.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/indicators/trend.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/indicators/trend_directional.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/indicators/trend_oscillators.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/indicators/trend_regression.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/indicators/volatility.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/indicators/volatility_price.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/indicators/volatility_stats.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/indicators/volume.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/indicators.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/lib.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/margin/calculator.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/margin/engine.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/margin/mod.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/market/china.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/market/core.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/market/corporate_action.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/market/fund.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/market/futures.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/market/manager.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/market/mod.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/market/option.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/market/simple.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/market/stock.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/model/corporate_action.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/model/instrument.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/model/market_data.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/model/mod.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/model/order.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/model/timer.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/model/types.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/order_manager.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/pipeline/mod.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/pipeline/processor.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/pipeline/runner.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/pipeline/stages.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/portfolio.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/risk/common.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/risk/config.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/risk/futures.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/risk/manager.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/risk/mod.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/risk/option.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/risk/portfolio.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/risk/rule.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/risk/stock.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/settlement/expiry.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/settlement/handler.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/settlement/manager.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/settlement/mod.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/settlement/option.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/src/statistics/mod.rs +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/BASELINE_REPORT.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/LEGACY_EXECUTION_CALLS.md +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/baselines/futures_margin/equity_curve.parquet +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/baselines/futures_margin/metrics.json +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/baselines/futures_margin/orders.parquet +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/baselines/option_basic/equity_curve.parquet +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/baselines/option_basic/metrics.json +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/baselines/option_basic/orders.parquet +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/baselines/stock_t1/equity_curve.parquet +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/baselines/stock_t1/metrics.json +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/baselines/stock_t1/orders.parquet +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/baselines/stock_t1/trades.parquet +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/current/futures_margin/equity_curve.parquet +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/current/option_basic/equity_curve.parquet +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/current/stock_t1/equity_curve.parquet +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/current/stock_t1/trades.parquet +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/data/future_margin.parquet +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/data/future_margin.parquet.sha256 +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/data/option_basic.parquet +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/data/option_basic.parquet.sha256 +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/data/stock_t1.parquet +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/data/stock_t1.parquet.sha256 +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/gen_data.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/runner.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/strategies/futures_margin.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/strategies/option_basic.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/strategies/stock_t1.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/golden/test_golden.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_account_risk_rules.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_custom_matcher.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_docs_api_examples.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_docs_links.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_engine.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_examples_regression.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_factor_engine.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_factor_ops.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_feed_adapter.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_gateway_callbacks.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_gateway_ctp_adapter.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_gateway_ctp_native.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_gateway_factory.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_gateway_mapper.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_gateway_registry.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_inspector.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_live_runner_broker_bridge.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_multisymbol_cross_section_consistency.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_orders_df.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_params_adapter.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_partial_filled_status.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_portfolio.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_quickstart_stream_consistency.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_report_helpers.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_report_plot_extensions.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_result_analysis_extensions.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_stop_orders.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_strategy_timers_indicators.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_t_plus_one.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_talib_backend.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_talib_compat.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_trades_df.py +0 -0
- {akquant-0.2.30 → akquant-0.2.32}/tests/test_version.py +0 -0
|
@@ -54,7 +54,7 @@ A strategy goes through the following stages from start to finish:
|
|
|
54
54
|
| `on_before_trading` | First entry into `Normal` session each local trading day | Pre-market checks, trading-date level signal preparation | `examples/50_framework_hooks_demo.py` |
|
|
55
55
|
| `on_pre_open` | Triggered by a framework timer before the first regular event of each trading day | Auction/pre-open signal generation with default next-open order semantics | `examples/52_pre_open_demo.py` |
|
|
56
56
|
| `on_daily_rebalance` | At most once per trading day, same phase as `on_before_trading` | Cross-sectional ranking and one-shot rebalance | `examples/strategies/05_stock_momentum_rotation_timer.py` |
|
|
57
|
-
| `on_after_trading` | When leaving
|
|
57
|
+
| `on_after_trading` | When leaving the regular trading session, or replayed on the next event if needed | End-of-day summaries, post-close cleanup, archiving | `examples/50_framework_hooks_demo.py` |
|
|
58
58
|
| `on_portfolio_update` | Incrementally when portfolio snapshot changes | Monitor cash/equity changes, push UI or alerts | `examples/50_framework_hooks_demo.py` |
|
|
59
59
|
| `on_error` | When any user callback raises | Record callback source and choose continue vs fail-fast | `examples/22_strategy_runtime_config_demo.py` |
|
|
60
60
|
| `on_timer` | When a registered timer fires | Scheduled rebalance, pre-market tasks, cadence checks | `examples/strategies/07_stock_momentum_rotation_on_timer.py` |
|
|
@@ -79,10 +79,11 @@ Notes:
|
|
|
79
79
|
|
|
80
80
|
* `on_reject` is emitted once per order id when the order first becomes `Rejected`.
|
|
81
81
|
* `on_pre_open` is emitted once per trading day before the first regular bar/tick callback of that day.
|
|
82
|
-
* `on_before_trading` is emitted once per local trading date when session
|
|
83
|
-
* `
|
|
82
|
+
* `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`.
|
|
83
|
+
* `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 `get_portfolio_value()` must not expose the current day's new bar or the current day's updated account view.
|
|
84
|
+
* `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.
|
|
84
85
|
* 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.
|
|
85
|
-
* Set `self.enable_precise_day_boundary_hooks = True` to enable boundary-timer based precise day hooks.
|
|
86
|
+
* Set `self.enable_precise_day_boundary_hooks = True` to enable boundary-timer based precise day hooks; this switch changes trigger precision only, not the history/account visibility window seen inside day-boundary callbacks.
|
|
86
87
|
* `on_portfolio_update` is incremental: emitted once at initialization, then only on order/trade or position-relevant price changes.
|
|
87
88
|
* Use `self.portfolio_update_eps` to filter tiny equity/cash changes (default `0.0`).
|
|
88
89
|
* During stop phase, pending `on_session_end` / `on_after_trading` are flushed before `on_stop`.
|
|
@@ -188,7 +189,7 @@ Practical tips:
|
|
|
188
189
|
Timing note:
|
|
189
190
|
|
|
190
191
|
* Do not treat `on_before_trading` as a stable same-day preparation stage that always runs before `on_pre_open`.
|
|
191
|
-
* On the default path, `on_pre_open` runs before the first regular event, while `on_before_trading` is usually emitted on that first regular event after the session
|
|
192
|
+
* On the default path, `on_pre_open` runs before the first regular event, while `on_before_trading` is usually emitted on that first regular event after the regular trading session begins.
|
|
192
193
|
* Even with `enable_precise_day_boundary_hooks`, the boundary-timer version of `on_before_trading` should not be used as a deterministic same-day predecessor for `on_pre_open`.
|
|
193
194
|
* For a true two-stage pattern, prepare in a later callback from the previous trading day and execute in the next trading day's `on_pre_open`, for example via a previous-day `on_timer` or `on_after_trading`.
|
|
194
195
|
* See `examples/53_timer_to_pre_open_demo.py`.
|
|
@@ -687,9 +687,10 @@ Strategy base class. Users should inherit from this class and override callback
|
|
|
687
687
|
* `on_expiry(event: Dict[str, Any])`: Triggered after an `expiry_date` driven settlement/removal is actually executed. Portfolio state is already updated when the callback runs. See `examples/49_on_expiry_demo.py` for a runnable example.
|
|
688
688
|
* `on_session_start(session, timestamp)`: Triggered on session transition start.
|
|
689
689
|
* `on_session_end(session, timestamp)`: Triggered on session transition end.
|
|
690
|
-
* `on_before_trading(trading_date, timestamp)`: Triggered once when
|
|
690
|
+
* `on_before_trading(trading_date, timestamp)`: Triggered once when the regular trading session starts each local day; on the default backtest path this session is usually exposed as `Continuous`. This callback follows a "previous trading day / previous snapshot only" visibility model.
|
|
691
691
|
* `on_pre_open(event: Dict[str, Any])`: Triggered once before the first regular event of each trading day. Use it for "pre-open decision, current open fill" workflows; default order semantics resolve to `price_basis=open, bar_offset=1, temporal=same_cycle`. See `examples/52_pre_open_demo.py`.
|
|
692
|
-
* `
|
|
692
|
+
* `on_daily_rebalance(trading_date, timestamp)`: Daily rebalance hook, triggered at most once per trading day and in the same phase as `on_before_trading`. It also exposes only previous-trading-day / previous-snapshot information.
|
|
693
|
+
* `on_after_trading(trading_date, timestamp)`: Triggered when leaving the regular trading session, or replayed on next event after day rollover.
|
|
693
694
|
* `on_portfolio_update(snapshot)`: Triggered when cash/equity/position snapshot changes.
|
|
694
695
|
* `on_error(error, source, payload=None)`: Triggered when user callback raises, then exception is re-raised by default.
|
|
695
696
|
* `on_timer(payload: str)`: Triggered by timer.
|
|
@@ -714,7 +715,7 @@ Note: if you do not pass an explicit `fill_policy` here, the framework defaults
|
|
|
714
715
|
* `self.position`: Position object for current symbol, with `size` and `available` properties.
|
|
715
716
|
* `self.now`: Current backtest time (`pd.Timestamp`).
|
|
716
717
|
* `self.runtime_config`: Runtime behavior config object (`StrategyRuntimeConfig`).
|
|
717
|
-
* `self.enable_precise_day_boundary_hooks`: Enable boundary timer based precise day hooks (default `False`).
|
|
718
|
+
* `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 `get_portfolio_value()` inside `on_before_trading` / `on_daily_rebalance`.
|
|
718
719
|
* `self.portfolio_update_eps`: Snapshot threshold; changes below it skip `on_portfolio_update` (default `0.0`).
|
|
719
720
|
* `self.error_mode`: Error handling mode, `"raise"` or `"continue"` (default `"raise"`).
|
|
720
721
|
* `self.re_raise_on_error`: Whether to re-raise user callback exception after `on_error` (default `True`).
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
var ENGLISH_PREFIX = /^\/en(?:\/|$)/;
|
|
5
|
+
var RESULT_LIST_SELECTOR = ".md-search-result__list";
|
|
6
|
+
var RESULT_ITEM_SELECTOR = ".md-search-result__item";
|
|
7
|
+
var RESULT_LINK_SELECTOR = ".md-search-result__link";
|
|
8
|
+
var SEARCH_QUERY_SELECTOR = 'input[data-md-component="search-query"]';
|
|
9
|
+
var EMPTY_STATE_ATTR = "data-akquant-locale-empty";
|
|
10
|
+
var rafId = null;
|
|
11
|
+
|
|
12
|
+
function getCurrentLocale() {
|
|
13
|
+
return ENGLISH_PREFIX.test(window.location.pathname) ? "en" : "zh";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function getResultPath(href) {
|
|
17
|
+
try {
|
|
18
|
+
return new URL(href, window.location.origin).pathname;
|
|
19
|
+
} catch (error) {
|
|
20
|
+
return "";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function matchesCurrentLocale(pathname, locale) {
|
|
25
|
+
if (!pathname) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
return locale === "en"
|
|
29
|
+
? ENGLISH_PREFIX.test(pathname)
|
|
30
|
+
: !ENGLISH_PREFIX.test(pathname);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getQueryText() {
|
|
34
|
+
var input = document.querySelector(SEARCH_QUERY_SELECTOR);
|
|
35
|
+
return input ? input.value.trim() : "";
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function getEmptyMessage(locale) {
|
|
39
|
+
return locale === "en"
|
|
40
|
+
? "No results in the current language. Switch language to search the translated page."
|
|
41
|
+
: "当前语言暂无匹配结果,可切换语言后重试。";
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function ensureEmptyState(list, locale, shouldShow) {
|
|
45
|
+
var existing = list.querySelector("[" + EMPTY_STATE_ATTR + "]");
|
|
46
|
+
|
|
47
|
+
if (!shouldShow) {
|
|
48
|
+
if (existing) {
|
|
49
|
+
existing.remove();
|
|
50
|
+
}
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (existing) {
|
|
55
|
+
existing.querySelector("p").textContent = getEmptyMessage(locale);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
var item = document.createElement("li");
|
|
60
|
+
item.className = "md-search-result__item";
|
|
61
|
+
item.setAttribute(EMPTY_STATE_ATTR, "true");
|
|
62
|
+
|
|
63
|
+
var article = document.createElement("article");
|
|
64
|
+
article.className = "md-search-result__article md-typeset";
|
|
65
|
+
|
|
66
|
+
var paragraph = document.createElement("p");
|
|
67
|
+
paragraph.textContent = getEmptyMessage(locale);
|
|
68
|
+
|
|
69
|
+
article.appendChild(paragraph);
|
|
70
|
+
item.appendChild(article);
|
|
71
|
+
list.appendChild(item);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function filterList(list) {
|
|
75
|
+
var locale = getCurrentLocale();
|
|
76
|
+
var items = Array.prototype.filter.call(
|
|
77
|
+
list.querySelectorAll(RESULT_ITEM_SELECTOR),
|
|
78
|
+
function (item) {
|
|
79
|
+
return !item.hasAttribute(EMPTY_STATE_ATTR);
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
if (!items.length) {
|
|
84
|
+
ensureEmptyState(list, locale, false);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
var visibleCount = 0;
|
|
89
|
+
|
|
90
|
+
items.forEach(function (item) {
|
|
91
|
+
var links = item.querySelectorAll(RESULT_LINK_SELECTOR);
|
|
92
|
+
var keep = Array.prototype.some.call(links, function (link) {
|
|
93
|
+
var href = link.getAttribute("href") || "";
|
|
94
|
+
return matchesCurrentLocale(getResultPath(href), locale);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
item.hidden = !keep;
|
|
98
|
+
if (keep) {
|
|
99
|
+
visibleCount += 1;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
ensureEmptyState(
|
|
104
|
+
list,
|
|
105
|
+
locale,
|
|
106
|
+
visibleCount === 0 && items.length > 0 && getQueryText().length > 0
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function filterAllSearchResults() {
|
|
111
|
+
document.querySelectorAll(RESULT_LIST_SELECTOR).forEach(filterList);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function scheduleFilter() {
|
|
115
|
+
if (rafId !== null) {
|
|
116
|
+
window.cancelAnimationFrame(rafId);
|
|
117
|
+
}
|
|
118
|
+
rafId = window.requestAnimationFrame(function () {
|
|
119
|
+
rafId = null;
|
|
120
|
+
filterAllSearchResults();
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
document.addEventListener("input", function (event) {
|
|
125
|
+
if (event.target && event.target.matches(SEARCH_QUERY_SELECTOR)) {
|
|
126
|
+
scheduleFilter();
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
window.addEventListener("hashchange", scheduleFilter);
|
|
131
|
+
window.addEventListener("pageshow", scheduleFilter);
|
|
132
|
+
document.addEventListener("DOMContentLoaded", scheduleFilter);
|
|
133
|
+
|
|
134
|
+
var observer = new MutationObserver(function () {
|
|
135
|
+
scheduleFilter();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
observer.observe(document.body, {
|
|
139
|
+
childList: true,
|
|
140
|
+
subtree: true,
|
|
141
|
+
});
|
|
142
|
+
})();
|
|
@@ -80,14 +80,15 @@
|
|
|
80
80
|
|
|
81
81
|
* `on_reject` 对同一订单 id 只触发一次。
|
|
82
82
|
* 回测中已终态拒单会通过上下文快照 `recent_rejected_orders` 在下一次事件分发时补发,避免因清理活跃订单导致漏触发。
|
|
83
|
-
* `on_before_trading`
|
|
83
|
+
* `on_before_trading` 在本地交易日首次进入常规交易会话时触发一次;默认回测路径下该会话通常表现为 `Continuous`。
|
|
84
84
|
* `on_pre_open` 在每个交易日的首个常规行情事件前,由框架预注册 timer 先触发一次。
|
|
85
85
|
* `on_daily_rebalance` 与 `on_before_trading` 同一阶段触发,每个交易日最多触发一次。
|
|
86
|
-
* `
|
|
86
|
+
* `on_before_trading` / `on_daily_rebalance` 始终按“前一交易日/前一时点信息可见”的语义工作;在这些回调里,`get_history()`、`get_account()`、`get_portfolio_value()` 不应看到当日新 bar 或当日更新后的账户视图。
|
|
87
|
+
* `on_after_trading` 在离开常规交易会话时触发;若先跨日再收到事件,会在下一事件补发上一交易日的 `on_after_trading`。
|
|
87
88
|
* `on_pre_open` 内若直接调用 `buy/sell/order_target_*` 且未显式传 `fill_policy`,框架会自动解析为 `price_basis=open, bar_offset=1, temporal=same_cycle`。
|
|
88
89
|
* 这里表达的是框架侧“盘前决策,本次 open 成交”的时序语义,不等同于交易所或券商柜台已经实现了集合竞价专用报单、撤单窗口控制或专有价格类型。
|
|
89
90
|
* 新股/新债打新不属于 `on_pre_open` 或当前统一 `submit_order(...)` 的默认承诺范围;若要支持,通常需要补齐 broker 专有字段与业务路由。
|
|
90
|
-
* 若需要更精确的交易日边界触发,可在策略中设置 `self.enable_precise_day_boundary_hooks = True
|
|
91
|
+
* 若需要更精确的交易日边界触发,可在策略中设置 `self.enable_precise_day_boundary_hooks = True`;该开关只影响 `on_before_trading` / `on_daily_rebalance` / `on_after_trading` 的触发精度,不改变这些日边界回调中的历史数据与账户快照可见窗口。
|
|
91
92
|
* `on_portfolio_update` 采用增量触发:初始化时触发一次,后续仅在订单/成交或持仓相关价格变化时触发。
|
|
92
93
|
* 可通过 `self.portfolio_update_eps` 过滤微小资产波动(默认 `0.0`,即不过滤)。
|
|
93
94
|
* 停止阶段会在 `on_stop` 之前补发待触发的 `on_session_end` / `on_after_trading`。
|
|
@@ -711,10 +711,10 @@ result = run_backtest(
|
|
|
711
711
|
* `on_expiry(event: Dict[str, Any])`: 到期结算回调。仅当引擎实际执行 `expiry_date` 驱动的到期结算/移除后触发;回调时账户状态已更新。示例见:`examples/49_on_expiry_demo.py`。
|
|
712
712
|
* `on_session_start(session, timestamp)`: 会话切换开始时触发。
|
|
713
713
|
* `on_session_end(session, timestamp)`: 会话切换结束时触发。
|
|
714
|
-
* `on_before_trading(trading_date, timestamp)`:
|
|
714
|
+
* `on_before_trading(trading_date, timestamp)`: 每个本地交易日首次进入常规交易会话时触发一次;默认回测路径下该会话通常表现为 `Continuous`。该回调按“前一交易日/前一时点信息可见”的语义工作。
|
|
715
715
|
* `on_pre_open(event: Dict[str, Any])`: 每个交易日首个常规行情事件前触发一次。适合“盘前决策,本次 open 成交”;默认下单语义会自动解析为 `price_basis=open, bar_offset=1, temporal=same_cycle`。示例见:`examples/52_pre_open_demo.py`。
|
|
716
|
-
* `on_daily_rebalance(trading_date, timestamp)`:
|
|
717
|
-
* `on_after_trading(trading_date, timestamp)`:
|
|
716
|
+
* `on_daily_rebalance(trading_date, timestamp)`: 交易日调仓钩子,每个交易日最多触发一次,与 `on_before_trading` 同阶段;该回调同样只暴露前一交易日/前一时点信息。
|
|
717
|
+
* `on_after_trading(trading_date, timestamp)`: 离开常规交易会话时触发;若先跨日则在下一事件补发。
|
|
718
718
|
* `on_portfolio_update(snapshot)`: 账户快照变化时触发。
|
|
719
719
|
* `on_error(error, source, payload=None)`: 用户回调抛异常时触发,默认触发后继续抛出。
|
|
720
720
|
* `on_timer(payload: str)`: 定时器触发。
|
|
@@ -739,7 +739,7 @@ def on_pre_open(self, event: Dict[str, Any]) -> None:
|
|
|
739
739
|
* `self.position`: 当前标的持仓辅助对象 (`Position`),包含 `size` 和 `available` 属性。
|
|
740
740
|
* `self.now`: 当前回测时间 (`pd.Timestamp`)。
|
|
741
741
|
* `self.runtime_config`: 运行时行为配置对象 (`StrategyRuntimeConfig`)。
|
|
742
|
-
* `self.enable_precise_day_boundary_hooks`: 是否启用边界定时器精确交易日钩子(默认 `False
|
|
742
|
+
* `self.enable_precise_day_boundary_hooks`: 是否启用边界定时器精确交易日钩子(默认 `False`)。该开关只影响日边界 hooks 的触发精度,不改变 `on_before_trading` / `on_daily_rebalance` 中 `get_history()`、`get_account()`、`get_portfolio_value()` 等接口的可见数据窗口。
|
|
743
743
|
* `self.portfolio_update_eps`: 账户快照更新阈值,低于该变化量不触发 `on_portfolio_update`(默认 `0.0`)。
|
|
744
744
|
* `self.error_mode`: 错误处理模式,`"raise"` 或 `"continue"`(默认 `"raise"`)。
|
|
745
745
|
* `self.re_raise_on_error`: 用户回调异常后是否继续抛出(默认 `True`)。
|
|
@@ -49,10 +49,6 @@ markdown_extensions:
|
|
|
49
49
|
- pymdownx.snippets
|
|
50
50
|
- pymdownx.superfences
|
|
51
51
|
|
|
52
|
-
extra_javascript:
|
|
53
|
-
- javascripts/mathjax.js
|
|
54
|
-
- https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js
|
|
55
|
-
|
|
56
52
|
plugins:
|
|
57
53
|
- search
|
|
58
54
|
- i18n:
|
|
@@ -304,6 +300,7 @@ extra:
|
|
|
304
300
|
|
|
305
301
|
extra_javascript:
|
|
306
302
|
- javascripts/mathjax.js
|
|
303
|
+
- javascripts/search-lang-filter.js
|
|
307
304
|
- https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js
|
|
308
305
|
|
|
309
306
|
copyright: Copyright © 2026 AKQuant Contributors
|
|
@@ -338,6 +338,11 @@ class Strategy:
|
|
|
338
338
|
_framework_boundary_timers_registered: bool
|
|
339
339
|
_framework_pre_open_timers_registered: bool
|
|
340
340
|
_framework_in_pre_open_phase: bool
|
|
341
|
+
_framework_phase: Optional[str]
|
|
342
|
+
_framework_history_cutoff_ns: Optional[int]
|
|
343
|
+
_framework_use_previous_account_snapshot: bool
|
|
344
|
+
_framework_previous_account_details: Optional[Dict[str, float]]
|
|
345
|
+
_framework_emit_previous_portfolio_snapshot: bool
|
|
341
346
|
_trading_day_bounds: Dict[str, Tuple[int, int]]
|
|
342
347
|
_oco_groups: Dict[str, set[str]]
|
|
343
348
|
_oco_order_to_group: Dict[str, str]
|
|
@@ -468,6 +473,11 @@ class Strategy:
|
|
|
468
473
|
instance._framework_boundary_timers_registered = False
|
|
469
474
|
instance._framework_pre_open_timers_registered = False
|
|
470
475
|
instance._framework_in_pre_open_phase = False
|
|
476
|
+
instance._framework_phase = None
|
|
477
|
+
instance._framework_history_cutoff_ns = None
|
|
478
|
+
instance._framework_use_previous_account_snapshot = False
|
|
479
|
+
instance._framework_previous_account_details = None
|
|
480
|
+
instance._framework_emit_previous_portfolio_snapshot = False
|
|
471
481
|
instance._trading_day_bounds = {}
|
|
472
482
|
instance._oco_groups = {}
|
|
473
483
|
instance._oco_order_to_group = {}
|
|
@@ -66,12 +66,8 @@ def on_bar_event(strategy: Any, bar: Bar, ctx: StrategyContext) -> None:
|
|
|
66
66
|
strategy._auto_configure_model()
|
|
67
67
|
|
|
68
68
|
previous_price = strategy._last_prices.get(bar.symbol)
|
|
69
|
-
strategy.current_bar =
|
|
69
|
+
strategy.current_bar = None
|
|
70
70
|
strategy.current_tick = None
|
|
71
|
-
if hasattr(strategy, "_update_incremental_indicators"):
|
|
72
|
-
strategy._update_incremental_indicators(bar)
|
|
73
|
-
strategy._last_prices[bar.symbol] = bar.close
|
|
74
|
-
strategy._bar_count += 1
|
|
75
71
|
|
|
76
72
|
if _is_before_active_start(strategy, int(bar.timestamp)):
|
|
77
73
|
return
|
|
@@ -79,6 +75,11 @@ def on_bar_event(strategy: Any, bar: Bar, ctx: StrategyContext) -> None:
|
|
|
79
75
|
if current_pos != 0 and previous_price is not None and previous_price != bar.close:
|
|
80
76
|
mark_portfolio_dirty(strategy)
|
|
81
77
|
dispatch_time_hooks(strategy)
|
|
78
|
+
strategy.current_bar = bar
|
|
79
|
+
if hasattr(strategy, "_update_incremental_indicators"):
|
|
80
|
+
strategy._update_incremental_indicators(bar)
|
|
81
|
+
strategy._last_prices[bar.symbol] = bar.close
|
|
82
|
+
strategy._bar_count += 1
|
|
82
83
|
dispatch_portfolio_update(strategy)
|
|
83
84
|
|
|
84
85
|
if strategy._bar_count < strategy.warmup_period:
|
|
@@ -125,9 +126,8 @@ def on_tick_event(strategy: Any, tick: Tick, ctx: StrategyContext) -> None:
|
|
|
125
126
|
strategy._check_order_events()
|
|
126
127
|
check_expiry_events(strategy)
|
|
127
128
|
previous_price = strategy._last_prices.get(tick.symbol)
|
|
128
|
-
strategy.current_tick = tick
|
|
129
129
|
strategy.current_bar = None
|
|
130
|
-
strategy.
|
|
130
|
+
strategy.current_tick = None
|
|
131
131
|
|
|
132
132
|
if _is_before_active_start(strategy, int(tick.timestamp)):
|
|
133
133
|
return
|
|
@@ -136,6 +136,8 @@ def on_tick_event(strategy: Any, tick: Tick, ctx: StrategyContext) -> None:
|
|
|
136
136
|
if current_pos != 0 and previous_price is not None and previous_price != tick.price:
|
|
137
137
|
mark_portfolio_dirty(strategy)
|
|
138
138
|
dispatch_time_hooks(strategy)
|
|
139
|
+
strategy.current_tick = tick
|
|
140
|
+
strategy._last_prices[tick.symbol] = tick.price
|
|
139
141
|
dispatch_portfolio_update(strategy)
|
|
140
142
|
call_user_callback(strategy, "on_tick", tick, payload=tick)
|
|
141
143
|
|
|
@@ -44,10 +44,18 @@ def _use_precise_day_boundary_hooks(strategy: Any) -> bool:
|
|
|
44
44
|
|
|
45
45
|
def _is_normal_session(session: Any) -> bool:
|
|
46
46
|
normal = getattr(TradingSession, "Normal", None)
|
|
47
|
-
|
|
48
|
-
return bool(session == normal)
|
|
47
|
+
continuous = getattr(TradingSession, "Continuous", None)
|
|
49
48
|
text = str(session).lower()
|
|
50
|
-
|
|
49
|
+
if (
|
|
50
|
+
text == "normal"
|
|
51
|
+
or text.endswith(".normal")
|
|
52
|
+
or text == "continuous"
|
|
53
|
+
or text.endswith(".continuous")
|
|
54
|
+
):
|
|
55
|
+
return True
|
|
56
|
+
if normal is not None or continuous is not None:
|
|
57
|
+
return bool(session == normal or session == continuous)
|
|
58
|
+
return False
|
|
51
59
|
|
|
52
60
|
|
|
53
61
|
def _is_pre_open_session(session: Any) -> bool:
|
|
@@ -138,27 +146,81 @@ def _should_reraise_on_error(strategy: Any) -> bool:
|
|
|
138
146
|
return bool(_runtime_option(strategy, "re_raise_on_error"))
|
|
139
147
|
|
|
140
148
|
|
|
149
|
+
def _snapshot_previous_account_details(strategy: Any) -> Optional[Dict[str, float]]:
|
|
150
|
+
"""Capture previous-snapshot derived account fields for framework phases."""
|
|
151
|
+
if strategy.ctx is None:
|
|
152
|
+
return None
|
|
153
|
+
from .strategy_trading_api import _calc_frozen_cash, _resolve_mark_price
|
|
154
|
+
|
|
155
|
+
short_market_value = 0.0
|
|
156
|
+
for sym, qty in strategy.ctx.positions.items():
|
|
157
|
+
qty_f = float(qty)
|
|
158
|
+
if qty_f >= 0.0:
|
|
159
|
+
continue
|
|
160
|
+
short_market_value += abs(qty_f) * _resolve_mark_price(strategy, str(sym))
|
|
161
|
+
return {
|
|
162
|
+
"frozen_cash": float(_calc_frozen_cash(strategy)),
|
|
163
|
+
"short_market_value": float(short_market_value),
|
|
164
|
+
"margin_accrued_interest": float(
|
|
165
|
+
getattr(strategy.ctx, "margin_accrued_interest", 0.0)
|
|
166
|
+
),
|
|
167
|
+
"margin_daily_interest": float(
|
|
168
|
+
getattr(strategy.ctx, "margin_daily_interest", 0.0)
|
|
169
|
+
),
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _run_in_framework_phase(
|
|
174
|
+
strategy: Any,
|
|
175
|
+
phase: str,
|
|
176
|
+
timestamp: int,
|
|
177
|
+
callback_name: str,
|
|
178
|
+
*args: Any,
|
|
179
|
+
payload: Optional[Any] = None,
|
|
180
|
+
) -> Any:
|
|
181
|
+
"""Run a callback with a framework phase and history visibility cutoff."""
|
|
182
|
+
previous_phase = getattr(strategy, "_framework_phase", None)
|
|
183
|
+
previous_cutoff = getattr(strategy, "_framework_history_cutoff_ns", None)
|
|
184
|
+
previous_pre_open = bool(getattr(strategy, "_framework_in_pre_open_phase", False))
|
|
185
|
+
previous_bar = getattr(strategy, "current_bar", None)
|
|
186
|
+
previous_tick = getattr(strategy, "current_tick", None)
|
|
187
|
+
previous_account_snapshot = bool(
|
|
188
|
+
getattr(strategy, "_framework_use_previous_account_snapshot", False)
|
|
189
|
+
)
|
|
190
|
+
previous_account_details = getattr(
|
|
191
|
+
strategy, "_framework_previous_account_details", None
|
|
192
|
+
)
|
|
193
|
+
strategy._framework_phase = phase
|
|
194
|
+
strategy._framework_history_cutoff_ns = int(timestamp)
|
|
195
|
+
strategy._framework_previous_account_details = _snapshot_previous_account_details(
|
|
196
|
+
strategy
|
|
197
|
+
)
|
|
198
|
+
strategy._framework_use_previous_account_snapshot = True
|
|
199
|
+
strategy.current_bar = None
|
|
200
|
+
strategy.current_tick = None
|
|
201
|
+
if phase == "pre_open":
|
|
202
|
+
strategy._framework_in_pre_open_phase = True
|
|
203
|
+
try:
|
|
204
|
+
return call_user_callback(strategy, callback_name, *args, payload=payload)
|
|
205
|
+
finally:
|
|
206
|
+
strategy._framework_phase = previous_phase
|
|
207
|
+
strategy._framework_history_cutoff_ns = previous_cutoff
|
|
208
|
+
strategy._framework_in_pre_open_phase = previous_pre_open
|
|
209
|
+
strategy._framework_use_previous_account_snapshot = previous_account_snapshot
|
|
210
|
+
strategy._framework_previous_account_details = previous_account_details
|
|
211
|
+
strategy.current_bar = previous_bar
|
|
212
|
+
strategy.current_tick = previous_tick
|
|
213
|
+
|
|
214
|
+
|
|
141
215
|
def _dispatch_daily_rebalance_if_needed(
|
|
142
216
|
strategy: Any, trading_date: Any, timestamp: int
|
|
143
217
|
) -> None:
|
|
144
218
|
if getattr(strategy, "_framework_daily_rebalance_done_date", None) == trading_date:
|
|
145
219
|
return
|
|
146
|
-
|
|
147
|
-
if event_type == "bar" and strategy.ctx is not None:
|
|
148
|
-
pending_date = getattr(
|
|
149
|
-
strategy,
|
|
150
|
-
"_framework_daily_rebalance_pending_date",
|
|
151
|
-
None,
|
|
152
|
-
)
|
|
153
|
-
if pending_date == trading_date:
|
|
154
|
-
return
|
|
155
|
-
schedule_ts = int(timestamp) + 1
|
|
156
|
-
payload = f"__framework_rebalance__|{trading_date}|{int(timestamp)}"
|
|
157
|
-
strategy.ctx.schedule(schedule_ts, payload)
|
|
158
|
-
strategy._framework_daily_rebalance_pending_date = trading_date
|
|
159
|
-
return
|
|
160
|
-
call_user_callback(
|
|
220
|
+
_run_in_framework_phase(
|
|
161
221
|
strategy,
|
|
222
|
+
"daily_rebalance",
|
|
223
|
+
timestamp,
|
|
162
224
|
"on_daily_rebalance",
|
|
163
225
|
trading_date,
|
|
164
226
|
timestamp,
|
|
@@ -201,12 +263,6 @@ def dispatch_time_hooks(strategy: Any) -> None:
|
|
|
201
263
|
current_date = ts.date()
|
|
202
264
|
current_session = getattr(strategy.ctx, "session", None)
|
|
203
265
|
use_precise_boundaries = _use_precise_day_boundary_hooks(strategy)
|
|
204
|
-
if (
|
|
205
|
-
not use_precise_boundaries
|
|
206
|
-
and getattr(strategy, "_framework_daily_rebalance_done_date", None)
|
|
207
|
-
!= current_date
|
|
208
|
-
):
|
|
209
|
-
_dispatch_daily_rebalance_if_needed(strategy, current_date, current_time)
|
|
210
266
|
|
|
211
267
|
last_date = getattr(strategy, "_framework_last_local_date", None)
|
|
212
268
|
before_done_date = getattr(strategy, "_framework_before_trading_done_date", None)
|
|
@@ -253,14 +309,23 @@ def dispatch_time_hooks(strategy: Any) -> None:
|
|
|
253
309
|
and getattr(strategy, "_framework_before_trading_done_date", None)
|
|
254
310
|
!= current_date
|
|
255
311
|
):
|
|
256
|
-
|
|
312
|
+
_run_in_framework_phase(
|
|
257
313
|
strategy,
|
|
314
|
+
"before_trading",
|
|
315
|
+
current_time,
|
|
258
316
|
"on_before_trading",
|
|
259
317
|
current_date,
|
|
260
318
|
current_time,
|
|
261
319
|
payload={"trading_date": current_date, "timestamp": current_time},
|
|
262
320
|
)
|
|
263
321
|
strategy._framework_before_trading_done_date = current_date
|
|
322
|
+
if (
|
|
323
|
+
not use_precise_boundaries
|
|
324
|
+
and _is_normal_session(current_session)
|
|
325
|
+
and getattr(strategy, "_framework_daily_rebalance_done_date", None)
|
|
326
|
+
!= current_date
|
|
327
|
+
):
|
|
328
|
+
_dispatch_daily_rebalance_if_needed(strategy, current_date, current_time)
|
|
264
329
|
|
|
265
330
|
if (
|
|
266
331
|
not use_precise_boundaries
|
|
@@ -343,8 +408,10 @@ def dispatch_boundary_timer(strategy: Any, payload: str) -> bool:
|
|
|
343
408
|
current_time = int(getattr(strategy.ctx, "current_time", 0))
|
|
344
409
|
if phase == "before":
|
|
345
410
|
if getattr(strategy, "_framework_before_trading_done_date", None) != day:
|
|
346
|
-
|
|
411
|
+
_run_in_framework_phase(
|
|
347
412
|
strategy,
|
|
413
|
+
"before_trading",
|
|
414
|
+
current_time,
|
|
348
415
|
"on_before_trading",
|
|
349
416
|
day,
|
|
350
417
|
current_time,
|
|
@@ -352,8 +419,10 @@ def dispatch_boundary_timer(strategy: Any, payload: str) -> bool:
|
|
|
352
419
|
)
|
|
353
420
|
strategy._framework_before_trading_done_date = day
|
|
354
421
|
if getattr(strategy, "_framework_daily_rebalance_done_date", None) != day:
|
|
355
|
-
|
|
422
|
+
_run_in_framework_phase(
|
|
356
423
|
strategy,
|
|
424
|
+
"daily_rebalance",
|
|
425
|
+
current_time,
|
|
357
426
|
"on_daily_rebalance",
|
|
358
427
|
day,
|
|
359
428
|
current_time,
|
|
@@ -403,11 +472,14 @@ def dispatch_pre_open_timer(strategy: Any, payload: str) -> bool:
|
|
|
403
472
|
return True
|
|
404
473
|
|
|
405
474
|
event = _build_pre_open_event(strategy, trading_date, source_timestamp)
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
475
|
+
_run_in_framework_phase(
|
|
476
|
+
strategy,
|
|
477
|
+
"pre_open",
|
|
478
|
+
source_timestamp,
|
|
479
|
+
"on_pre_open",
|
|
480
|
+
event,
|
|
481
|
+
payload=event,
|
|
482
|
+
)
|
|
411
483
|
strategy._framework_pre_open_done_date = trading_date
|
|
412
484
|
return True
|
|
413
485
|
|
|
@@ -434,8 +506,10 @@ def dispatch_daily_rebalance_timer(strategy: Any, payload: str) -> bool:
|
|
|
434
506
|
|
|
435
507
|
done_date = getattr(strategy, "_framework_daily_rebalance_done_date", None)
|
|
436
508
|
if done_date != trading_date:
|
|
437
|
-
|
|
509
|
+
_run_in_framework_phase(
|
|
438
510
|
strategy,
|
|
511
|
+
"daily_rebalance",
|
|
512
|
+
source_timestamp,
|
|
439
513
|
"on_daily_rebalance",
|
|
440
514
|
trading_date,
|
|
441
515
|
source_timestamp,
|
|
@@ -468,8 +542,21 @@ def dispatch_portfolio_update(strategy: Any) -> None:
|
|
|
468
542
|
available_positions = {
|
|
469
543
|
k: float(v) for k, v in dict(strategy.ctx.available_positions).items()
|
|
470
544
|
}
|
|
471
|
-
|
|
472
|
-
|
|
545
|
+
use_previous_snapshot = bool(
|
|
546
|
+
getattr(strategy, "_framework_emit_previous_portfolio_snapshot", False)
|
|
547
|
+
)
|
|
548
|
+
previous_override = bool(
|
|
549
|
+
getattr(strategy, "_framework_use_previous_account_snapshot", False)
|
|
550
|
+
)
|
|
551
|
+
strategy._framework_use_previous_account_snapshot = use_previous_snapshot
|
|
552
|
+
try:
|
|
553
|
+
equity = float(strategy.get_portfolio_value())
|
|
554
|
+
market_value = float(equity - cash)
|
|
555
|
+
account_snapshot = strategy.get_account()
|
|
556
|
+
finally:
|
|
557
|
+
strategy._framework_use_previous_account_snapshot = previous_override
|
|
558
|
+
if use_previous_snapshot:
|
|
559
|
+
strategy._framework_emit_previous_portfolio_snapshot = False
|
|
473
560
|
|
|
474
561
|
state_key: Tuple[Any, ...] = (
|
|
475
562
|
round(cash, 8),
|
|
@@ -497,7 +584,6 @@ def dispatch_portfolio_update(strategy: Any) -> None:
|
|
|
497
584
|
return
|
|
498
585
|
|
|
499
586
|
strategy._framework_last_portfolio_state = state_key
|
|
500
|
-
account_snapshot = strategy.get_account()
|
|
501
587
|
snapshot: Dict[str, Any] = {
|
|
502
588
|
"timestamp": current_time,
|
|
503
589
|
"session": session,
|
|
@@ -509,8 +595,15 @@ def dispatch_portfolio_update(strategy: Any) -> None:
|
|
|
509
595
|
"margin": float(account_snapshot.get("margin", 0.0)),
|
|
510
596
|
"frozen_cash": float(account_snapshot.get("frozen_cash", 0.0)),
|
|
511
597
|
}
|
|
512
|
-
|
|
513
|
-
|
|
598
|
+
callback_override = bool(
|
|
599
|
+
getattr(strategy, "_framework_use_previous_account_snapshot", False)
|
|
600
|
+
)
|
|
601
|
+
strategy._framework_use_previous_account_snapshot = use_previous_snapshot
|
|
602
|
+
try:
|
|
603
|
+
call_user_callback(strategy, "on_portfolio_update", snapshot, payload=snapshot)
|
|
604
|
+
strategy._framework_portfolio_dirty = False
|
|
605
|
+
finally:
|
|
606
|
+
strategy._framework_use_previous_account_snapshot = callback_override
|
|
514
607
|
|
|
515
608
|
|
|
516
609
|
def dispatch_shutdown_hooks(strategy: Any) -> None:
|
|
@@ -567,6 +660,16 @@ def ensure_framework_state(strategy: Any) -> None:
|
|
|
567
660
|
strategy._framework_pre_open_timers_registered = False
|
|
568
661
|
if not hasattr(strategy, "_framework_in_pre_open_phase"):
|
|
569
662
|
strategy._framework_in_pre_open_phase = False
|
|
663
|
+
if not hasattr(strategy, "_framework_phase"):
|
|
664
|
+
strategy._framework_phase = None
|
|
665
|
+
if not hasattr(strategy, "_framework_history_cutoff_ns"):
|
|
666
|
+
strategy._framework_history_cutoff_ns = None
|
|
667
|
+
if not hasattr(strategy, "_framework_use_previous_account_snapshot"):
|
|
668
|
+
strategy._framework_use_previous_account_snapshot = False
|
|
669
|
+
if not hasattr(strategy, "_framework_previous_account_details"):
|
|
670
|
+
strategy._framework_previous_account_details = None
|
|
671
|
+
if not hasattr(strategy, "_framework_emit_previous_portfolio_snapshot"):
|
|
672
|
+
strategy._framework_emit_previous_portfolio_snapshot = False
|
|
570
673
|
if not hasattr(strategy, "_framework_last_portfolio_state"):
|
|
571
674
|
strategy._framework_last_portfolio_state = None
|
|
572
675
|
if not hasattr(strategy, "_framework_portfolio_dirty"):
|