akquant 0.2.44__tar.gz → 0.2.45__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.
Files changed (494) hide show
  1. {akquant-0.2.44 → akquant-0.2.45}/Cargo.lock +1 -1
  2. {akquant-0.2.44 → akquant-0.2.45}/Cargo.toml +1 -1
  3. {akquant-0.2.44 → akquant-0.2.45}/PKG-INFO +1 -1
  4. {akquant-0.2.44 → akquant-0.2.45}/docs/en/guide/analysis.md +1 -1
  5. {akquant-0.2.44 → akquant-0.2.45}/docs/en/reference/api.md +2 -1
  6. {akquant-0.2.44 → akquant-0.2.45}/docs/en/start/quickstart.md +1 -1
  7. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/guide/analysis.md +1 -1
  8. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/reference/api.md +2 -1
  9. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/start/quickstart.md +1 -1
  10. {akquant-0.2.44 → akquant-0.2.45}/pyproject.toml +1 -1
  11. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/akquant.pyi +2 -0
  12. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/backtest/result.py +91 -2
  13. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/plot/report.py +8 -7
  14. {akquant-0.2.44 → akquant-0.2.45}/tests/test_engine.py +51 -0
  15. {akquant-0.2.44 → akquant-0.2.45}/tests/test_report_plot_extensions.py +47 -0
  16. {akquant-0.2.44 → akquant-0.2.45}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  17. {akquant-0.2.44 → akquant-0.2.45}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  18. {akquant-0.2.44 → akquant-0.2.45}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  19. {akquant-0.2.44 → akquant-0.2.45}/.github/workflows/deploy-docs.yml +0 -0
  20. {akquant-0.2.44 → akquant-0.2.45}/.github/workflows/docs-quality.yml +0 -0
  21. {akquant-0.2.44 → akquant-0.2.45}/.github/workflows/release.yml +0 -0
  22. {akquant-0.2.44 → akquant-0.2.45}/.gitignore +0 -0
  23. {akquant-0.2.44 → akquant-0.2.45}/.pre-commit-config.yaml +0 -0
  24. {akquant-0.2.44 → akquant-0.2.45}/CHANGELOG.md +0 -0
  25. {akquant-0.2.44 → akquant-0.2.45}/CODE_OF_CONDUCT.md +0 -0
  26. {akquant-0.2.44 → akquant-0.2.45}/CONTRIBUTING.md +0 -0
  27. {akquant-0.2.44 → akquant-0.2.45}/LICENSE +0 -0
  28. {akquant-0.2.44 → akquant-0.2.45}/README.md +0 -0
  29. {akquant-0.2.44 → akquant-0.2.45}/assets/dashboard_preview.png +0 -0
  30. {akquant-0.2.44 → akquant-0.2.45}/assets/logo.svg +0 -0
  31. {akquant-0.2.44 → akquant-0.2.45}/assets/social_preview.png +0 -0
  32. {akquant-0.2.44 → akquant-0.2.45}/docs/CNAME +0 -0
  33. {akquant-0.2.44 → akquant-0.2.45}/docs/assets/akquant-icon.svg +0 -0
  34. {akquant-0.2.44 → akquant-0.2.45}/docs/assets/akquant-logo.svg +0 -0
  35. {akquant-0.2.44 → akquant-0.2.45}/docs/assets/reports/akquant_report.html +0 -0
  36. {akquant-0.2.44 → akquant-0.2.45}/docs/en/advanced/analyzer_plugin_spec.md +0 -0
  37. {akquant-0.2.44 → akquant-0.2.45}/docs/en/advanced/broker_capability_matrix.md +0 -0
  38. {akquant-0.2.44 → akquant-0.2.45}/docs/en/advanced/custom_broker_production_checklist.md +0 -0
  39. {akquant-0.2.44 → akquant-0.2.45}/docs/en/advanced/custom_broker_registry.md +0 -0
  40. {akquant-0.2.44 → akquant-0.2.45}/docs/en/advanced/data_feed_adapter_spec.md +0 -0
  41. {akquant-0.2.44 → akquant-0.2.45}/docs/en/advanced/live_functional_quickstart.md +0 -0
  42. {akquant-0.2.44 → akquant-0.2.45}/docs/en/advanced/llm.md +0 -0
  43. {akquant-0.2.44 → akquant-0.2.45}/docs/en/advanced/ml.md +0 -0
  44. {akquant-0.2.44 → akquant-0.2.45}/docs/en/advanced/multi_strategy_guide.md +0 -0
  45. {akquant-0.2.44 → akquant-0.2.45}/docs/en/advanced/multi_timeframe_feed_api.md +0 -0
  46. {akquant-0.2.44 → akquant-0.2.45}/docs/en/advanced/runtime_config.md +0 -0
  47. {akquant-0.2.44 → akquant-0.2.45}/docs/en/advanced/strategy_style_decision.md +0 -0
  48. {akquant-0.2.44 → akquant-0.2.45}/docs/en/advanced/timezone.md +0 -0
  49. {akquant-0.2.44 → akquant-0.2.45}/docs/en/advanced/warm_start.md +0 -0
  50. {akquant-0.2.44 → akquant-0.2.45}/docs/en/guide/cross_section_checklist.md +0 -0
  51. {akquant-0.2.44 → akquant-0.2.45}/docs/en/guide/custom_indicator.md +0 -0
  52. {akquant-0.2.44 → akquant-0.2.45}/docs/en/guide/data.md +0 -0
  53. {akquant-0.2.44 → akquant-0.2.45}/docs/en/guide/examples.md +0 -0
  54. {akquant-0.2.44 → akquant-0.2.45}/docs/en/guide/factor.md +0 -0
  55. {akquant-0.2.44 → akquant-0.2.45}/docs/en/guide/indicator_scenario_quickref.md +0 -0
  56. {akquant-0.2.44 → akquant-0.2.45}/docs/en/guide/optimization.md +0 -0
  57. {akquant-0.2.44 → akquant-0.2.45}/docs/en/guide/python_basics.md +0 -0
  58. {akquant-0.2.44 → akquant-0.2.45}/docs/en/guide/quant_basics.md +0 -0
  59. {akquant-0.2.44 → akquant-0.2.45}/docs/en/guide/rust_indicator_reference.md +0 -0
  60. {akquant-0.2.44 → akquant-0.2.45}/docs/en/guide/strategy.md +0 -0
  61. {akquant-0.2.44 → akquant-0.2.45}/docs/en/guide/talib_indicator_playbook.md +0 -0
  62. {akquant-0.2.44 → akquant-0.2.45}/docs/en/guide/testing.md +0 -0
  63. {akquant-0.2.44 → akquant-0.2.45}/docs/en/guide/visualization.md +0 -0
  64. {akquant-0.2.44 → akquant-0.2.45}/docs/en/index.md +0 -0
  65. {akquant-0.2.44 → akquant-0.2.45}/docs/en/meta/architecture.md +0 -0
  66. {akquant-0.2.44 → akquant-0.2.45}/docs/en/meta/internals.md +0 -0
  67. {akquant-0.2.44 → akquant-0.2.45}/docs/en/start/first_strategy.md +0 -0
  68. {akquant-0.2.44 → akquant-0.2.45}/docs/en/start/installation.md +0 -0
  69. {akquant-0.2.44 → akquant-0.2.45}/docs/en/start/setup_guide.md +0 -0
  70. {akquant-0.2.44 → akquant-0.2.45}/docs/en/textbook/01_foundations.md +0 -0
  71. {akquant-0.2.44 → akquant-0.2.45}/docs/en/textbook/02_programming.md +0 -0
  72. {akquant-0.2.44 → akquant-0.2.45}/docs/en/textbook/03_data.md +0 -0
  73. {akquant-0.2.44 → akquant-0.2.45}/docs/en/textbook/04_backtest_engine.md +0 -0
  74. {akquant-0.2.44 → akquant-0.2.45}/docs/en/textbook/05_strategy.md +0 -0
  75. {akquant-0.2.44 → akquant-0.2.45}/docs/en/textbook/06_stock_a.md +0 -0
  76. {akquant-0.2.44 → akquant-0.2.45}/docs/en/textbook/07_futures.md +0 -0
  77. {akquant-0.2.44 → akquant-0.2.45}/docs/en/textbook/08_options.md +0 -0
  78. {akquant-0.2.44 → akquant-0.2.45}/docs/en/textbook/09_funds.md +0 -0
  79. {akquant-0.2.44 → akquant-0.2.45}/docs/en/textbook/10_analysis.md +0 -0
  80. {akquant-0.2.44 → akquant-0.2.45}/docs/en/textbook/11_optimization.md +0 -0
  81. {akquant-0.2.44 → akquant-0.2.45}/docs/en/textbook/12_ml.md +0 -0
  82. {akquant-0.2.44 → akquant-0.2.45}/docs/en/textbook/13_visualization.md +0 -0
  83. {akquant-0.2.44 → akquant-0.2.45}/docs/en/textbook/14_factor.md +0 -0
  84. {akquant-0.2.44 → akquant-0.2.45}/docs/en/textbook/15_live_trading.md +0 -0
  85. {akquant-0.2.44 → akquant-0.2.45}/docs/en/textbook/16_rust_indicators.md +0 -0
  86. {akquant-0.2.44 → akquant-0.2.45}/docs/en/textbook/index.md +0 -0
  87. {akquant-0.2.44 → akquant-0.2.45}/docs/javascripts/mathjax.js +0 -0
  88. {akquant-0.2.44 → akquant-0.2.45}/docs/javascripts/search-lang-filter.js +0 -0
  89. {akquant-0.2.44 → akquant-0.2.45}/docs/robots.txt +0 -0
  90. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/advanced/analyzer_plugin_spec.md +0 -0
  91. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/advanced/broker_capability_matrix.md +0 -0
  92. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/advanced/custom_broker_production_checklist.md +0 -0
  93. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/advanced/custom_broker_registry.md +0 -0
  94. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/advanced/data_feed_adapter_spec.md +0 -0
  95. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/advanced/live_functional_quickstart.md +0 -0
  96. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/advanced/llm.md +0 -0
  97. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/advanced/ml.md +0 -0
  98. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/advanced/multi_strategy_guide.md +0 -0
  99. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/advanced/multi_timeframe_feed_api.md +0 -0
  100. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/advanced/runtime_config.md +0 -0
  101. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/advanced/strategy_style_decision.md +0 -0
  102. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/advanced/timezone.md +0 -0
  103. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/advanced/warm_start.md +0 -0
  104. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/guide/cross_section_checklist.md +0 -0
  105. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/guide/custom_indicator.md +0 -0
  106. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/guide/data.md +0 -0
  107. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/guide/examples.md +0 -0
  108. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/guide/factor.md +0 -0
  109. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/guide/indicator_scenario_quickref.md +0 -0
  110. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/guide/optimization.md +0 -0
  111. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/guide/python_basics.md +0 -0
  112. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/guide/quant_basics.md +0 -0
  113. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/guide/rust_indicator_reference.md +0 -0
  114. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/guide/strategy.md +0 -0
  115. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/guide/talib_indicator_playbook.md +0 -0
  116. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/guide/testing.md +0 -0
  117. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/guide/visualization.md +0 -0
  118. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/index.md +0 -0
  119. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/meta/architecture.md +0 -0
  120. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/meta/internals.md +0 -0
  121. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/start/first_strategy.md +0 -0
  122. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/start/installation.md +0 -0
  123. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/start/setup_guide.md +0 -0
  124. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/textbook/01_foundations.md +0 -0
  125. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/textbook/02_programming.md +0 -0
  126. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/textbook/03_data.md +0 -0
  127. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/textbook/04_backtest_engine.md +0 -0
  128. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/textbook/05_strategy.md +0 -0
  129. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/textbook/06_stock_a.md +0 -0
  130. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/textbook/07_futures.md +0 -0
  131. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/textbook/08_options.md +0 -0
  132. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/textbook/09_funds.md +0 -0
  133. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/textbook/10_analysis.md +0 -0
  134. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/textbook/11_optimization.md +0 -0
  135. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/textbook/12_ml.md +0 -0
  136. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/textbook/13_visualization.md +0 -0
  137. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/textbook/14_factor.md +0 -0
  138. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/textbook/15_live_trading.md +0 -0
  139. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/textbook/16_rust_indicators.md +0 -0
  140. {akquant-0.2.44 → akquant-0.2.45}/docs/zh/textbook/index.md +0 -0
  141. {akquant-0.2.44 → akquant-0.2.45}/examples/01_quickstart.py +0 -0
  142. {akquant-0.2.44 → akquant-0.2.45}/examples/02_parameter_optimization.py +0 -0
  143. {akquant-0.2.44 → akquant-0.2.45}/examples/03_parameter_optimization_advanced.py +0 -0
  144. {akquant-0.2.44 → akquant-0.2.45}/examples/04_mixed_assets.py +0 -0
  145. {akquant-0.2.44 → akquant-0.2.45}/examples/05_live_trading_ctp.py +0 -0
  146. {akquant-0.2.44 → akquant-0.2.45}/examples/06_complex_orders.py +0 -0
  147. {akquant-0.2.44 → akquant-0.2.45}/examples/07_option_test.py +0 -0
  148. {akquant-0.2.44 → akquant-0.2.45}/examples/08_event_callbacks.py +0 -0
  149. {akquant-0.2.44 → akquant-0.2.45}/examples/09_ml_framework.py +0 -0
  150. {akquant-0.2.44 → akquant-0.2.45}/examples/10_ml_walk_forward.py +0 -0
  151. {akquant-0.2.44 → akquant-0.2.45}/examples/11_plot_visualization.py +0 -0
  152. {akquant-0.2.44 → akquant-0.2.45}/examples/12_wfo_integrated.py +0 -0
  153. {akquant-0.2.44 → akquant-0.2.45}/examples/13_quantstats_report.py +0 -0
  154. {akquant-0.2.44 → akquant-0.2.45}/examples/14_multi_frequency.py +0 -0
  155. {akquant-0.2.44 → akquant-0.2.45}/examples/15_plot_intraday.py +0 -0
  156. {akquant-0.2.44 → akquant-0.2.45}/examples/16_adj_returns_signal.py +0 -0
  157. {akquant-0.2.44 → akquant-0.2.45}/examples/17_readme_demo.py +0 -0
  158. {akquant-0.2.44 → akquant-0.2.45}/examples/18_benchmark_multisymbol.py +0 -0
  159. {akquant-0.2.44 → akquant-0.2.45}/examples/19_factor_expression.py +0 -0
  160. {akquant-0.2.44 → akquant-0.2.45}/examples/20_risk_management_demo.py +0 -0
  161. {akquant-0.2.44 → akquant-0.2.45}/examples/21_warm_start_demo.py +0 -0
  162. {akquant-0.2.44 → akquant-0.2.45}/examples/22_strategy_runtime_config_demo.py +0 -0
  163. {akquant-0.2.44 → akquant-0.2.45}/examples/23_functional_callbacks_demo.py +0 -0
  164. {akquant-0.2.44 → akquant-0.2.45}/examples/24_functional_tick_simulation_demo.py +0 -0
  165. {akquant-0.2.44 → akquant-0.2.45}/examples/25_streaming_backtest_demo.py +0 -0
  166. {akquant-0.2.44 → akquant-0.2.45}/examples/26_streaming_quickstart.py +0 -0
  167. {akquant-0.2.44 → akquant-0.2.45}/examples/27_streaming_monitoring_console.py +0 -0
  168. {akquant-0.2.44 → akquant-0.2.45}/examples/28_streaming_alerts_and_persist.py +0 -0
  169. {akquant-0.2.44 → akquant-0.2.45}/examples/29_streaming_event_report.py +0 -0
  170. {akquant-0.2.44 → akquant-0.2.45}/examples/30_streaming_report_oneclick.py +0 -0
  171. {akquant-0.2.44 → akquant-0.2.45}/examples/31_streaming_live_console.py +0 -0
  172. {akquant-0.2.44 → akquant-0.2.45}/examples/32_streaming_live_web.py +0 -0
  173. {akquant-0.2.44 → akquant-0.2.45}/examples/33_report_and_analysis_outputs.py +0 -0
  174. {akquant-0.2.44 → akquant-0.2.45}/examples/34_multi_strategy_demo.py +0 -0
  175. {akquant-0.2.44 → akquant-0.2.45}/examples/35_custom_broker_registry_demo.py +0 -0
  176. {akquant-0.2.44 → akquant-0.2.45}/examples/36_trailing_orders.py +0 -0
  177. {akquant-0.2.44 → akquant-0.2.45}/examples/37_feed_replay_alignment_demo.py +0 -0
  178. {akquant-0.2.44 → akquant-0.2.45}/examples/38_live_functional_strategy_demo.py +0 -0
  179. {akquant-0.2.44 → akquant-0.2.45}/examples/39_live_broker_submit_order_demo.py +0 -0
  180. {akquant-0.2.44 → akquant-0.2.45}/examples/40_functional_multi_slot_risk_demo.py +0 -0
  181. {akquant-0.2.44 → akquant-0.2.45}/examples/41_live_multi_slot_orchestration_demo.py +0 -0
  182. {akquant-0.2.44 → akquant-0.2.45}/examples/42_live_broker_event_audit_demo.py +0 -0
  183. {akquant-0.2.44 → akquant-0.2.45}/examples/43_target_weights_rebalance.py +0 -0
  184. {akquant-0.2.44 → akquant-0.2.45}/examples/44_strategy_source_loader_demo.py +0 -0
  185. {akquant-0.2.44 → akquant-0.2.45}/examples/45_talib_indicator_playbook_demo.py +0 -0
  186. {akquant-0.2.44 → akquant-0.2.45}/examples/46_broker_profile_demo.py +0 -0
  187. {akquant-0.2.44 → akquant-0.2.45}/examples/47_margin_liquidation_audit_demo.py +0 -0
  188. {akquant-0.2.44 → akquant-0.2.45}/examples/48_margin_liquidation_priority_compare.py +0 -0
  189. {akquant-0.2.44 → akquant-0.2.45}/examples/49_on_expiry_demo.py +0 -0
  190. {akquant-0.2.44 → akquant-0.2.45}/examples/50_framework_hooks_demo.py +0 -0
  191. {akquant-0.2.44 → akquant-0.2.45}/examples/51_class_tick_callbacks_demo.py +0 -0
  192. {akquant-0.2.44 → akquant-0.2.45}/examples/52_pre_open_demo.py +0 -0
  193. {akquant-0.2.44 → akquant-0.2.45}/examples/53_timer_to_pre_open_demo.py +0 -0
  194. {akquant-0.2.44 → akquant-0.2.45}/examples/54_functional_pre_open_demo.py +0 -0
  195. {akquant-0.2.44 → akquant-0.2.45}/examples/55_functional_ml_walk_forward.py +0 -0
  196. {akquant-0.2.44 → akquant-0.2.45}/examples/56_functional_warm_start_demo.py +0 -0
  197. {akquant-0.2.44 → akquant-0.2.45}/examples/57_functional_multi_slot_warm_start_demo.py +0 -0
  198. {akquant-0.2.44 → akquant-0.2.45}/examples/58_incremental_bootstrap_demo.py +0 -0
  199. {akquant-0.2.44 → akquant-0.2.45}/examples/59_akshare_etf_rotation.py +0 -0
  200. {akquant-0.2.44 → akquant-0.2.45}/examples/60_custom_indicator_demo.py +0 -0
  201. {akquant-0.2.44 → akquant-0.2.45}/examples/61_indicator_visualization_export_demo.py +0 -0
  202. {akquant-0.2.44 → akquant-0.2.45}/examples/62_indicator_streaming_demo.py +0 -0
  203. {akquant-0.2.44 → akquant-0.2.45}/examples/63_indicator_ws_bridge_demo.py +0 -0
  204. {akquant-0.2.44 → akquant-0.2.45}/examples/64_indicator_live_web.py +0 -0
  205. {akquant-0.2.44 → akquant-0.2.45}/examples/README.md +0 -0
  206. {akquant-0.2.44 → akquant-0.2.45}/examples/benchmark_utils.py +0 -0
  207. {akquant-0.2.44 → akquant-0.2.45}/examples/pb_mock.py +0 -0
  208. {akquant-0.2.44 → akquant-0.2.45}/examples/strategies/01_stock_dual_moving_average.py +0 -0
  209. {akquant-0.2.44 → akquant-0.2.45}/examples/strategies/02_stock_grid_trading.py +0 -0
  210. {akquant-0.2.44 → akquant-0.2.45}/examples/strategies/03_stock_atr_breakout.py +0 -0
  211. {akquant-0.2.44 → akquant-0.2.45}/examples/strategies/04_stock_momentum_rotation.py +0 -0
  212. {akquant-0.2.44 → akquant-0.2.45}/examples/strategies/05_stock_momentum_rotation_timer.py +0 -0
  213. {akquant-0.2.44 → akquant-0.2.45}/examples/strategies/06_stock_momentum_rotation_bucket.py +0 -0
  214. {akquant-0.2.44 → akquant-0.2.45}/examples/strategies/07_stock_momentum_rotation_on_timer.py +0 -0
  215. {akquant-0.2.44 → akquant-0.2.45}/examples/strategies/08_target_positions_long_short.py +0 -0
  216. {akquant-0.2.44 → akquant-0.2.45}/examples/strategies/09_stock_momentum_rotation_after_bar.py +0 -0
  217. {akquant-0.2.44 → akquant-0.2.45}/examples/strategies/README.md +0 -0
  218. {akquant-0.2.44 → akquant-0.2.45}/examples/textbook/ch01_quickstart.py +0 -0
  219. {akquant-0.2.44 → akquant-0.2.45}/examples/textbook/ch02_programming.py +0 -0
  220. {akquant-0.2.44 → akquant-0.2.45}/examples/textbook/ch03_data.py +0 -0
  221. {akquant-0.2.44 → akquant-0.2.45}/examples/textbook/ch04_comparison.py +0 -0
  222. {akquant-0.2.44 → akquant-0.2.45}/examples/textbook/ch05_strategy.py +0 -0
  223. {akquant-0.2.44 → akquant-0.2.45}/examples/textbook/ch06_stock_a.py +0 -0
  224. {akquant-0.2.44 → akquant-0.2.45}/examples/textbook/ch07_futures.py +0 -0
  225. {akquant-0.2.44 → akquant-0.2.45}/examples/textbook/ch08_options.py +0 -0
  226. {akquant-0.2.44 → akquant-0.2.45}/examples/textbook/ch09_funds.py +0 -0
  227. {akquant-0.2.44 → akquant-0.2.45}/examples/textbook/ch09_portfolio.py +0 -0
  228. {akquant-0.2.44 → akquant-0.2.45}/examples/textbook/ch10_analysis.py +0 -0
  229. {akquant-0.2.44 → akquant-0.2.45}/examples/textbook/ch11_optimization.py +0 -0
  230. {akquant-0.2.44 → akquant-0.2.45}/examples/textbook/ch12_ml.py +0 -0
  231. {akquant-0.2.44 → akquant-0.2.45}/examples/textbook/ch13_visualization.py +0 -0
  232. {akquant-0.2.44 → akquant-0.2.45}/examples/textbook/ch14_factor.py +0 -0
  233. {akquant-0.2.44 → akquant-0.2.45}/examples/textbook/ch15_live_trading.py +0 -0
  234. {akquant-0.2.44 → akquant-0.2.45}/examples/textbook/ch15_strategy_loader.py +0 -0
  235. {akquant-0.2.44 → akquant-0.2.45}/mkdocs.yml +0 -0
  236. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/__init__.py +0 -0
  237. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/analysis/__init__.py +0 -0
  238. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/analysis/benchmark.py +0 -0
  239. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/analyzer_plugin.py +0 -0
  240. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/backtest/__init__.py +0 -0
  241. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/backtest/__init__.pyi +0 -0
  242. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/backtest/engine.py +0 -0
  243. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/checkpoint.py +0 -0
  244. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/config.py +0 -0
  245. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/data.py +0 -0
  246. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/factor/__init__.py +0 -0
  247. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/factor/engine.py +0 -0
  248. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/factor/ops.py +0 -0
  249. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/factor/parser.py +0 -0
  250. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/feed_adapter.py +0 -0
  251. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/fund/__init__.py +0 -0
  252. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/futures/__init__.py +0 -0
  253. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/__init__.py +0 -0
  254. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/base.py +0 -0
  255. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/broker_event_bridge.py +0 -0
  256. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/broker_event_mapper.py +0 -0
  257. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/broker_models.py +0 -0
  258. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/broker_recovery.py +0 -0
  259. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/broker_runtime.py +0 -0
  260. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/brokers/__init__.py +0 -0
  261. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/brokers/ctp/__init__.py +0 -0
  262. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/brokers/ctp/adapter.py +0 -0
  263. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/brokers/ctp/native.py +0 -0
  264. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/brokers/miniqmt/__init__.py +0 -0
  265. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/brokers/miniqmt/stub.py +0 -0
  266. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/brokers/ptrade/__init__.py +0 -0
  267. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/brokers/ptrade/stub.py +0 -0
  268. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/ctp_adapter.py +0 -0
  269. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/ctp_native.py +0 -0
  270. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/factory.py +0 -0
  271. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/mapper.py +0 -0
  272. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/miniqmt.py +0 -0
  273. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/models.py +0 -0
  274. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/order_submitter.py +0 -0
  275. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/protocols.py +0 -0
  276. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/ptrade.py +0 -0
  277. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/gateway/registry.py +0 -0
  278. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/indicator.py +0 -0
  279. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/indicator_recording.py +0 -0
  280. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/indicator_stream.py +0 -0
  281. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/live.py +0 -0
  282. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/log.py +0 -0
  283. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/ml/__init__.py +0 -0
  284. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/ml/model.py +0 -0
  285. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/optimize.py +0 -0
  286. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/option/__init__.py +0 -0
  287. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/params.py +0 -0
  288. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/params_adapter.py +0 -0
  289. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/plot/__init__.py +0 -0
  290. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/plot/analysis.py +0 -0
  291. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/plot/dashboard.py +0 -0
  292. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/plot/indicator.py +0 -0
  293. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/plot/strategy.py +0 -0
  294. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/plot/utils.py +0 -0
  295. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/py.typed +0 -0
  296. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/risk.py +0 -0
  297. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/sizer.py +0 -0
  298. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/stock/__init__.py +0 -0
  299. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/strategy.py +0 -0
  300. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/strategy_events.py +0 -0
  301. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/strategy_framework_hooks.py +0 -0
  302. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/strategy_history.py +0 -0
  303. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/strategy_loader.py +0 -0
  304. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/strategy_logging.py +0 -0
  305. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/strategy_ml.py +0 -0
  306. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/strategy_order_events.py +0 -0
  307. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/strategy_position.py +0 -0
  308. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/strategy_scheduler.py +0 -0
  309. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/strategy_time.py +0 -0
  310. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/strategy_trading_api.py +0 -0
  311. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/talib/__init__.py +0 -0
  312. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/talib/backend.py +0 -0
  313. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/talib/core.py +0 -0
  314. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/talib/funcs.py +0 -0
  315. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/utils/__init__.py +0 -0
  316. {akquant-0.2.44 → akquant-0.2.45}/python/akquant/utils/inspector.py +0 -0
  317. {akquant-0.2.44 → akquant-0.2.45}/requirements-dev.txt +0 -0
  318. {akquant-0.2.44 → akquant-0.2.45}/scripts/cargo-test.sh +0 -0
  319. {akquant-0.2.44 → akquant-0.2.45}/scripts/check_docs_api_examples.py +0 -0
  320. {akquant-0.2.44 → akquant-0.2.45}/scripts/check_docs_links.py +0 -0
  321. {akquant-0.2.44 → akquant-0.2.45}/scripts/dev-check.sh +0 -0
  322. {akquant-0.2.44 → akquant-0.2.45}/scripts/find_legacy_execution_policy_calls.py +0 -0
  323. {akquant-0.2.44 → akquant-0.2.45}/scripts/golden_baseline_report.py +0 -0
  324. {akquant-0.2.44 → akquant-0.2.45}/src/account.rs +0 -0
  325. {akquant-0.2.44 → akquant-0.2.45}/src/analysis/mod.rs +0 -0
  326. {akquant-0.2.44 → akquant-0.2.45}/src/analysis/python.rs +0 -0
  327. {akquant-0.2.44 → akquant-0.2.45}/src/analysis/result.rs +0 -0
  328. {akquant-0.2.44 → akquant-0.2.45}/src/analysis/tests.rs +0 -0
  329. {akquant-0.2.44 → akquant-0.2.45}/src/analysis/tracker.rs +0 -0
  330. {akquant-0.2.44 → akquant-0.2.45}/src/analysis/types.rs +0 -0
  331. {akquant-0.2.44 → akquant-0.2.45}/src/bin/stub_gen.rs +0 -0
  332. {akquant-0.2.44 → akquant-0.2.45}/src/clock.rs +0 -0
  333. {akquant-0.2.44 → akquant-0.2.45}/src/context.rs +0 -0
  334. {akquant-0.2.44 → akquant-0.2.45}/src/data/aggregator.rs +0 -0
  335. {akquant-0.2.44 → akquant-0.2.45}/src/data/batch.rs +0 -0
  336. {akquant-0.2.44 → akquant-0.2.45}/src/data/client.rs +0 -0
  337. {akquant-0.2.44 → akquant-0.2.45}/src/data/feed.rs +0 -0
  338. {akquant-0.2.44 → akquant-0.2.45}/src/data/mod.rs +0 -0
  339. {akquant-0.2.44 → akquant-0.2.45}/src/engine/core.rs +0 -0
  340. {akquant-0.2.44 → akquant-0.2.45}/src/engine/mod.rs +0 -0
  341. {akquant-0.2.44 → akquant-0.2.45}/src/engine/python.rs +0 -0
  342. {akquant-0.2.44 → akquant-0.2.45}/src/engine/state.rs +0 -0
  343. {akquant-0.2.44 → akquant-0.2.45}/src/error.rs +0 -0
  344. {akquant-0.2.44 → akquant-0.2.45}/src/event.rs +0 -0
  345. {akquant-0.2.44 → akquant-0.2.45}/src/event_manager.rs +0 -0
  346. {akquant-0.2.44 → akquant-0.2.45}/src/execution/common.rs +0 -0
  347. {akquant-0.2.44 → akquant-0.2.45}/src/execution/crypto.rs +0 -0
  348. {akquant-0.2.44 → akquant-0.2.45}/src/execution/forex.rs +0 -0
  349. {akquant-0.2.44 → akquant-0.2.45}/src/execution/futures.rs +0 -0
  350. {akquant-0.2.44 → akquant-0.2.45}/src/execution/matcher.rs +0 -0
  351. {akquant-0.2.44 → akquant-0.2.45}/src/execution/mod.rs +0 -0
  352. {akquant-0.2.44 → akquant-0.2.45}/src/execution/option.rs +0 -0
  353. {akquant-0.2.44 → akquant-0.2.45}/src/execution/python.rs +0 -0
  354. {akquant-0.2.44 → akquant-0.2.45}/src/execution/realtime.rs +0 -0
  355. {akquant-0.2.44 → akquant-0.2.45}/src/execution/simulated.rs +0 -0
  356. {akquant-0.2.44 → akquant-0.2.45}/src/execution/slippage.rs +0 -0
  357. {akquant-0.2.44 → akquant-0.2.45}/src/execution/stock.rs +0 -0
  358. {akquant-0.2.44 → akquant-0.2.45}/src/history.rs +0 -0
  359. {akquant-0.2.44 → akquant-0.2.45}/src/indicators/momentum.rs +0 -0
  360. {akquant-0.2.44 → akquant-0.2.45}/src/indicators/momentum_oscillators.rs +0 -0
  361. {akquant-0.2.44 → akquant-0.2.45}/src/indicators/momentum_rates.rs +0 -0
  362. {akquant-0.2.44 → akquant-0.2.45}/src/indicators/moving_average.rs +0 -0
  363. {akquant-0.2.44 → akquant-0.2.45}/src/indicators/moving_average_compound.rs +0 -0
  364. {akquant-0.2.44 → akquant-0.2.45}/src/indicators/moving_average_core.rs +0 -0
  365. {akquant-0.2.44 → akquant-0.2.45}/src/indicators/moving_average_transforms.rs +0 -0
  366. {akquant-0.2.44 → akquant-0.2.45}/src/indicators/moving_average_windowed.rs +0 -0
  367. {akquant-0.2.44 → akquant-0.2.45}/src/indicators/trend.rs +0 -0
  368. {akquant-0.2.44 → akquant-0.2.45}/src/indicators/trend_directional.rs +0 -0
  369. {akquant-0.2.44 → akquant-0.2.45}/src/indicators/trend_oscillators.rs +0 -0
  370. {akquant-0.2.44 → akquant-0.2.45}/src/indicators/trend_regression.rs +0 -0
  371. {akquant-0.2.44 → akquant-0.2.45}/src/indicators/volatility.rs +0 -0
  372. {akquant-0.2.44 → akquant-0.2.45}/src/indicators/volatility_price.rs +0 -0
  373. {akquant-0.2.44 → akquant-0.2.45}/src/indicators/volatility_stats.rs +0 -0
  374. {akquant-0.2.44 → akquant-0.2.45}/src/indicators/volume.rs +0 -0
  375. {akquant-0.2.44 → akquant-0.2.45}/src/indicators.rs +0 -0
  376. {akquant-0.2.44 → akquant-0.2.45}/src/lib.rs +0 -0
  377. {akquant-0.2.44 → akquant-0.2.45}/src/log_context.rs +0 -0
  378. {akquant-0.2.44 → akquant-0.2.45}/src/margin/calculator.rs +0 -0
  379. {akquant-0.2.44 → akquant-0.2.45}/src/margin/engine.rs +0 -0
  380. {akquant-0.2.44 → akquant-0.2.45}/src/margin/mod.rs +0 -0
  381. {akquant-0.2.44 → akquant-0.2.45}/src/market/china.rs +0 -0
  382. {akquant-0.2.44 → akquant-0.2.45}/src/market/core.rs +0 -0
  383. {akquant-0.2.44 → akquant-0.2.45}/src/market/corporate_action.rs +0 -0
  384. {akquant-0.2.44 → akquant-0.2.45}/src/market/fund.rs +0 -0
  385. {akquant-0.2.44 → akquant-0.2.45}/src/market/futures.rs +0 -0
  386. {akquant-0.2.44 → akquant-0.2.45}/src/market/manager.rs +0 -0
  387. {akquant-0.2.44 → akquant-0.2.45}/src/market/mod.rs +0 -0
  388. {akquant-0.2.44 → akquant-0.2.45}/src/market/option.rs +0 -0
  389. {akquant-0.2.44 → akquant-0.2.45}/src/market/simple.rs +0 -0
  390. {akquant-0.2.44 → akquant-0.2.45}/src/market/stock.rs +0 -0
  391. {akquant-0.2.44 → akquant-0.2.45}/src/model/corporate_action.rs +0 -0
  392. {akquant-0.2.44 → akquant-0.2.45}/src/model/instrument.rs +0 -0
  393. {akquant-0.2.44 → akquant-0.2.45}/src/model/market_data.rs +0 -0
  394. {akquant-0.2.44 → akquant-0.2.45}/src/model/mod.rs +0 -0
  395. {akquant-0.2.44 → akquant-0.2.45}/src/model/order.rs +0 -0
  396. {akquant-0.2.44 → akquant-0.2.45}/src/model/timer.rs +0 -0
  397. {akquant-0.2.44 → akquant-0.2.45}/src/model/types.rs +0 -0
  398. {akquant-0.2.44 → akquant-0.2.45}/src/order_manager.rs +0 -0
  399. {akquant-0.2.44 → akquant-0.2.45}/src/pipeline/mod.rs +0 -0
  400. {akquant-0.2.44 → akquant-0.2.45}/src/pipeline/processor.rs +0 -0
  401. {akquant-0.2.44 → akquant-0.2.45}/src/pipeline/runner.rs +0 -0
  402. {akquant-0.2.44 → akquant-0.2.45}/src/pipeline/stages.rs +0 -0
  403. {akquant-0.2.44 → akquant-0.2.45}/src/portfolio.rs +0 -0
  404. {akquant-0.2.44 → akquant-0.2.45}/src/risk/common.rs +0 -0
  405. {akquant-0.2.44 → akquant-0.2.45}/src/risk/config.rs +0 -0
  406. {akquant-0.2.44 → akquant-0.2.45}/src/risk/futures.rs +0 -0
  407. {akquant-0.2.44 → akquant-0.2.45}/src/risk/manager.rs +0 -0
  408. {akquant-0.2.44 → akquant-0.2.45}/src/risk/mod.rs +0 -0
  409. {akquant-0.2.44 → akquant-0.2.45}/src/risk/option.rs +0 -0
  410. {akquant-0.2.44 → akquant-0.2.45}/src/risk/portfolio.rs +0 -0
  411. {akquant-0.2.44 → akquant-0.2.45}/src/risk/rule.rs +0 -0
  412. {akquant-0.2.44 → akquant-0.2.45}/src/risk/stock.rs +0 -0
  413. {akquant-0.2.44 → akquant-0.2.45}/src/settlement/expiry.rs +0 -0
  414. {akquant-0.2.44 → akquant-0.2.45}/src/settlement/handler.rs +0 -0
  415. {akquant-0.2.44 → akquant-0.2.45}/src/settlement/manager.rs +0 -0
  416. {akquant-0.2.44 → akquant-0.2.45}/src/settlement/mod.rs +0 -0
  417. {akquant-0.2.44 → akquant-0.2.45}/src/settlement/option.rs +0 -0
  418. {akquant-0.2.44 → akquant-0.2.45}/src/statistics/mod.rs +0 -0
  419. {akquant-0.2.44 → akquant-0.2.45}/tests/gateway_contract/test_event_bridge_contract.py +0 -0
  420. {akquant-0.2.44 → akquant-0.2.45}/tests/gateway_contract/test_recovery_contract.py +0 -0
  421. {akquant-0.2.44 → akquant-0.2.45}/tests/gateway_contract/test_submitter_contract.py +0 -0
  422. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/BASELINE_REPORT.md +0 -0
  423. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/LEGACY_EXECUTION_CALLS.md +0 -0
  424. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/baselines/futures_margin/equity_curve.parquet +0 -0
  425. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/baselines/futures_margin/metrics.json +0 -0
  426. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/baselines/futures_margin/orders.parquet +0 -0
  427. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/baselines/option_basic/equity_curve.parquet +0 -0
  428. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/baselines/option_basic/metrics.json +0 -0
  429. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/baselines/option_basic/orders.parquet +0 -0
  430. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/baselines/stock_t1/equity_curve.parquet +0 -0
  431. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/baselines/stock_t1/metrics.json +0 -0
  432. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/baselines/stock_t1/orders.parquet +0 -0
  433. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/baselines/stock_t1/trades.parquet +0 -0
  434. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/current/futures_margin/equity_curve.parquet +0 -0
  435. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/current/futures_margin/metrics.json +0 -0
  436. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/current/futures_margin/orders.parquet +0 -0
  437. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/current/option_basic/equity_curve.parquet +0 -0
  438. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/current/option_basic/metrics.json +0 -0
  439. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/current/option_basic/orders.parquet +0 -0
  440. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/current/stock_t1/equity_curve.parquet +0 -0
  441. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/current/stock_t1/metrics.json +0 -0
  442. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/current/stock_t1/orders.parquet +0 -0
  443. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/current/stock_t1/trades.parquet +0 -0
  444. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/data/future_margin.parquet +0 -0
  445. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/data/future_margin.parquet.sha256 +0 -0
  446. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/data/option_basic.parquet +0 -0
  447. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/data/option_basic.parquet.sha256 +0 -0
  448. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/data/stock_t1.parquet +0 -0
  449. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/data/stock_t1.parquet.sha256 +0 -0
  450. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/gen_data.py +0 -0
  451. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/runner.py +0 -0
  452. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/strategies/futures_margin.py +0 -0
  453. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/strategies/option_basic.py +0 -0
  454. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/strategies/stock_t1.py +0 -0
  455. {akquant-0.2.44 → akquant-0.2.45}/tests/golden/test_golden.py +0 -0
  456. {akquant-0.2.44 → akquant-0.2.45}/tests/test_account_risk_rules.py +0 -0
  457. {akquant-0.2.44 → akquant-0.2.45}/tests/test_custom_matcher.py +0 -0
  458. {akquant-0.2.44 → akquant-0.2.45}/tests/test_data_catalog.py +0 -0
  459. {akquant-0.2.44 → akquant-0.2.45}/tests/test_docs_api_examples.py +0 -0
  460. {akquant-0.2.44 → akquant-0.2.45}/tests/test_docs_links.py +0 -0
  461. {akquant-0.2.44 → akquant-0.2.45}/tests/test_examples_regression.py +0 -0
  462. {akquant-0.2.44 → akquant-0.2.45}/tests/test_factor_engine.py +0 -0
  463. {akquant-0.2.44 → akquant-0.2.45}/tests/test_factor_ops.py +0 -0
  464. {akquant-0.2.44 → akquant-0.2.45}/tests/test_feed_adapter.py +0 -0
  465. {akquant-0.2.44 → akquant-0.2.45}/tests/test_gateway_brokers_paths.py +0 -0
  466. {akquant-0.2.44 → akquant-0.2.45}/tests/test_gateway_callbacks.py +0 -0
  467. {akquant-0.2.44 → akquant-0.2.45}/tests/test_gateway_ctp_adapter.py +0 -0
  468. {akquant-0.2.44 → akquant-0.2.45}/tests/test_gateway_ctp_native.py +0 -0
  469. {akquant-0.2.44 → akquant-0.2.45}/tests/test_gateway_factory.py +0 -0
  470. {akquant-0.2.44 → akquant-0.2.45}/tests/test_gateway_mapper.py +0 -0
  471. {akquant-0.2.44 → akquant-0.2.45}/tests/test_gateway_registry.py +0 -0
  472. {akquant-0.2.44 → akquant-0.2.45}/tests/test_indicator_live_web_example.py +0 -0
  473. {akquant-0.2.44 → akquant-0.2.45}/tests/test_indicator_recording.py +0 -0
  474. {akquant-0.2.44 → akquant-0.2.45}/tests/test_inspector.py +0 -0
  475. {akquant-0.2.44 → akquant-0.2.45}/tests/test_live_runner.py +0 -0
  476. {akquant-0.2.44 → akquant-0.2.45}/tests/test_live_runner_broker_bridge.py +0 -0
  477. {akquant-0.2.44 → akquant-0.2.45}/tests/test_live_runner_broker_recovery.py +0 -0
  478. {akquant-0.2.44 → akquant-0.2.45}/tests/test_live_runner_broker_submitter.py +0 -0
  479. {akquant-0.2.44 → akquant-0.2.45}/tests/test_multisymbol_cross_section_consistency.py +0 -0
  480. {akquant-0.2.44 → akquant-0.2.45}/tests/test_orders_df.py +0 -0
  481. {akquant-0.2.44 → akquant-0.2.45}/tests/test_params_adapter.py +0 -0
  482. {akquant-0.2.44 → akquant-0.2.45}/tests/test_partial_filled_status.py +0 -0
  483. {akquant-0.2.44 → akquant-0.2.45}/tests/test_portfolio.py +0 -0
  484. {akquant-0.2.44 → akquant-0.2.45}/tests/test_quickstart_stream_consistency.py +0 -0
  485. {akquant-0.2.44 → akquant-0.2.45}/tests/test_report_helpers.py +0 -0
  486. {akquant-0.2.44 → akquant-0.2.45}/tests/test_result_analysis_extensions.py +0 -0
  487. {akquant-0.2.44 → akquant-0.2.45}/tests/test_stop_orders.py +0 -0
  488. {akquant-0.2.44 → akquant-0.2.45}/tests/test_strategy_extras.py +0 -0
  489. {akquant-0.2.44 → akquant-0.2.45}/tests/test_strategy_timers_indicators.py +0 -0
  490. {akquant-0.2.44 → akquant-0.2.45}/tests/test_t_plus_one.py +0 -0
  491. {akquant-0.2.44 → akquant-0.2.45}/tests/test_talib_backend.py +0 -0
  492. {akquant-0.2.44 → akquant-0.2.45}/tests/test_talib_compat.py +0 -0
  493. {akquant-0.2.44 → akquant-0.2.45}/tests/test_trades_df.py +0 -0
  494. {akquant-0.2.44 → akquant-0.2.45}/tests/test_version.py +0 -0
@@ -30,7 +30,7 @@ dependencies = [
30
30
 
31
31
  [[package]]
32
32
  name = "akquant"
33
- version = "0.2.44"
33
+ version = "0.2.45"
34
34
  dependencies = [
35
35
  "anyhow",
36
36
  "chrono",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "akquant"
3
- version = "0.2.44"
3
+ version = "0.2.45"
4
4
  edition = "2024"
5
5
  description = "High-performance quantitative trading framework based on Rust and Python"
6
6
  license = "MIT"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: akquant
3
- Version: 0.2.44
3
+ Version: 0.2.45
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -17,7 +17,7 @@ result.report(
17
17
  filename="report.html",
18
18
  show=True, # Set to True to open in browser automatically (default is False)
19
19
  compact_currency=True, # Format amount columns as K/M/B in report tables
20
- curve_freq="raw", # "raw" keeps all bars, "D" uses end-of-day points
20
+ curve_freq="D", # Default uses end-of-day points; "raw" keeps all bars
21
21
  )
22
22
  ```
23
23
 
@@ -1113,10 +1113,11 @@ Backtest result object.
1113
1113
  * `capacity_df(freq="D")`: Capacity proxy metrics (order count, fill rates, turnover).
1114
1114
  * `benchmark_analysis(benchmark=None, curve_freq="raw")`: Return a structured benchmark analysis payload for frontends and APIs.
1115
1115
  * `export_benchmark_analysis(path, benchmark=None, format="json", curve_freq="raw")`: Persist benchmark analysis as JSON or parquet artifacts.
1116
+ * `top_reject_reason_types(top_n=10)`: Aggregate reject counts by normalized reject type and include a sample detail row.
1116
1117
  * `orders_by_strategy()`: Strategy-ownership order aggregation by `owner_strategy_id`.
1117
1118
  * `executions_by_strategy()`: Strategy-ownership execution aggregation by `owner_strategy_id`.
1118
1119
  * `get_event_stats()`: Unified stream summary stats (for example `processed_events`, `dropped_event_count`, `callback_error_count`, `backpressure_policy`, `stream_mode`).
1119
- * `report(..., curve_freq="raw" | "D")`: Generate HTML report with raw or daily curve frequency.
1120
+ * `report(..., curve_freq="D" | "raw")`: Generate HTML report with daily end-of-day curves by default, or switch back to raw frequency.
1120
1121
 
1121
1122
  ```python
1122
1123
  orders_by_strategy = result.orders_by_strategy()
@@ -285,7 +285,7 @@ result.report(
285
285
  show=True,
286
286
  filename="report.html",
287
287
  compact_currency=True,
288
- curve_freq="raw",
288
+ curve_freq="D",
289
289
  )
290
290
 
291
291
  result.report(
@@ -177,7 +177,7 @@ result.report(
177
177
  filename="report.html",
178
178
  show=True, # 设为 True 以自动在浏览器中打开 (默认为 False)
179
179
  compact_currency=True, # 金额列使用 K/M/B 紧凑显示 (默认为 True)
180
- curve_freq="raw", # "raw" 保留原始频率,"D" 使用日频末值
180
+ curve_freq="D", # 默认即为 "D","raw" 可保留原始频率
181
181
  )
182
182
  ```
183
183
 
@@ -1187,10 +1187,11 @@ class RiskConfig:
1187
1187
  * `capacity_df(freq="D")`: 容量代理指标(订单数、成交率、换手)。
1188
1188
  * `benchmark_analysis(benchmark=None, curve_freq="raw")`: 返回结构化 benchmark analysis,可直接供前端/API 使用。
1189
1189
  * `export_benchmark_analysis(path, benchmark=None, format="json", curve_freq="raw")`: 将 benchmark analysis 导出为 JSON 或 parquet 产物。
1190
+ * `top_reject_reason_types(top_n=10)`: 按拒单类型聚合拒单统计,并附带一条示例明细。
1190
1191
  * `orders_by_strategy()`: 按 `owner_strategy_id` 聚合订单统计。
1191
1192
  * `executions_by_strategy()`: 按 `owner_strategy_id` 聚合成交流水统计。
1192
1193
  * `get_event_stats()`: 返回流式事件统计摘要(如 `processed_events`、`dropped_event_count`、`callback_error_count`、`backpressure_policy`、`stream_mode`)。
1193
- * `report(..., curve_freq="raw" | "D")`: 生成 HTML 报告时,可选原始频率或日频末值曲线。
1194
+ * `report(..., curve_freq="D" | "raw")`: 生成 HTML 报告时,默认使用日频末值曲线,也可切回原始频率。
1194
1195
 
1195
1196
  ```python
1196
1197
  orders_by_strategy = result.orders_by_strategy()
@@ -319,7 +319,7 @@ result.report(
319
319
  show=True,
320
320
  filename="report.html",
321
321
  compact_currency=True,
322
- curve_freq="raw",
322
+ curve_freq="D",
323
323
  )
324
324
 
325
325
  result.report(
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "akquant"
7
- version = "0.2.44"
7
+ version = "0.2.45"
8
8
  description = "High-performance quantitative trading framework based on Rust and Python"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT License"}
@@ -326,6 +326,8 @@ class BacktestResult:
326
326
  theme: str = ...,
327
327
  filename: typing.Optional[str] = ...,
328
328
  ) -> typing.Any: ...
329
+ def top_reject_reasons(self, top_n: int = ...) -> typing.Any: ...
330
+ def top_reject_reason_types(self, top_n: int = ...) -> typing.Any: ...
329
331
  def report(
330
332
  self,
331
333
  title: str = ...,
@@ -1167,6 +1167,37 @@ class BacktestResult:
1167
1167
  "other_risk_reject_count": (~known_mask).astype(int),
1168
1168
  }
1169
1169
 
1170
+ @staticmethod
1171
+ def _classify_reject_reason(reason: Any) -> str:
1172
+ """Map raw reject messages to stable report-friendly categories."""
1173
+ reason_text = str(reason).strip()
1174
+ if not reason_text:
1175
+ return "Empty Reject Reason"
1176
+ reason_lower = reason_text.lower()
1177
+ if "insufficient margin" in reason_lower:
1178
+ return "Insufficient Margin"
1179
+ if "daily loss" in reason_lower or "stop-loss threshold" in reason_lower:
1180
+ return "Daily Loss Limit"
1181
+ if "drawdown" in reason_lower:
1182
+ return "Drawdown Limit"
1183
+ if "reduce_only mode" in reason_lower or "cooldown" in reason_lower:
1184
+ return "Reduce-Only / Cooldown"
1185
+ if (
1186
+ "projected position" in reason_lower
1187
+ or "available position" in reason_lower
1188
+ or "is restricted" in reason_lower
1189
+ ):
1190
+ return "Position Limit"
1191
+ if "order quantity" in reason_lower or "lot size" in reason_lower:
1192
+ return "Order Size Limit"
1193
+ if "order value" in reason_lower:
1194
+ return "Order Value Limit"
1195
+ if "portfolio risk budget" in reason_lower:
1196
+ return "Portfolio Risk Budget"
1197
+ if "risk budget" in reason_lower and "strategy" in reason_lower:
1198
+ return "Strategy Risk Budget"
1199
+ return "Other"
1200
+
1170
1201
  def top_reject_reasons(self, top_n: int = 10) -> pd.DataFrame:
1171
1202
  """Get Top-N rejection reasons from orders."""
1172
1203
  columns = ["reject_reason", "count", "ratio"]
@@ -1212,6 +1243,64 @@ class BacktestResult:
1212
1243
  frame["ratio"] = frame["count"] / float(total)
1213
1244
  return cast(pd.DataFrame, frame.reset_index(drop=True))
1214
1245
 
1246
+ def top_reject_reason_types(self, top_n: int = 10) -> pd.DataFrame:
1247
+ """Get Top-N rejection categories with a sample raw message."""
1248
+ columns = ["reject_reason_type", "sample_reject_reason", "count", "ratio"]
1249
+ if top_n <= 0:
1250
+ return pd.DataFrame(columns=columns)
1251
+
1252
+ orders = self.orders_df.copy()
1253
+ if orders.empty:
1254
+ return pd.DataFrame(columns=columns)
1255
+
1256
+ if "reject_reason" not in orders.columns:
1257
+ orders["reject_reason"] = ""
1258
+ if "status" not in orders.columns:
1259
+ orders["status"] = ""
1260
+ reject_reason = orders["reject_reason"].fillna("").astype(str)
1261
+ status = orders["status"].fillna("").astype(str)
1262
+ rejected_mask = (reject_reason.str.len() > 0) | status.str.contains(
1263
+ "Rejected", case=False, regex=False
1264
+ )
1265
+ rejected = orders.loc[rejected_mask].copy()
1266
+ if rejected.empty:
1267
+ return pd.DataFrame(columns=columns)
1268
+
1269
+ cleaned_reason = (
1270
+ rejected["reject_reason"]
1271
+ .fillna("")
1272
+ .astype(str)
1273
+ .str.strip()
1274
+ .replace("", "(empty reject reason)")
1275
+ )
1276
+ classified = cleaned_reason.map(self._classify_reject_reason)
1277
+ total = int(len(classified))
1278
+ if total <= 0:
1279
+ return pd.DataFrame(columns=columns)
1280
+
1281
+ frame = pd.DataFrame(
1282
+ {
1283
+ "reject_reason_type": classified.astype(str),
1284
+ "sample_reject_reason": cleaned_reason.astype(str),
1285
+ }
1286
+ )
1287
+ grouped = (
1288
+ frame.groupby("reject_reason_type", sort=False)
1289
+ .agg(
1290
+ count=("reject_reason_type", "size"),
1291
+ sample_reject_reason=(
1292
+ "sample_reject_reason",
1293
+ lambda series: cast(str, series.value_counts().index[0]),
1294
+ ),
1295
+ )
1296
+ .reset_index()
1297
+ )
1298
+ grouped = grouped.sort_values(
1299
+ ["count", "reject_reason_type"], ascending=[False, True]
1300
+ ).head(top_n)
1301
+ grouped["ratio"] = grouped["count"] / float(total)
1302
+ return cast(pd.DataFrame, grouped[columns].reset_index(drop=True))
1303
+
1215
1304
  def risk_rejections_by_strategy(self) -> pd.DataFrame:
1216
1305
  """Get strategy-level risk rejection breakdown table."""
1217
1306
  orders = self.orders_df.copy()
@@ -1765,7 +1854,7 @@ class BacktestResult:
1765
1854
  indicator_symbol: Optional[str] = None,
1766
1855
  indicator_include_warmup: bool = True,
1767
1856
  benchmark: Optional[Union[str, pd.Series]] = None,
1768
- curve_freq: str = "raw",
1857
+ curve_freq: str = "D",
1769
1858
  ) -> None:
1770
1859
  """
1771
1860
  生成 HTML 策略回测报告 (便捷方法).
@@ -1784,7 +1873,7 @@ class BacktestResult:
1784
1873
  :param indicator_symbol: 可选标的过滤,仅展示指定标的指标
1785
1874
  :param indicator_include_warmup: 是否在指标报告区块中保留预热点
1786
1875
  :param benchmark: 基准收益序列 (pd.Series) 或基准标识字符串
1787
- :param curve_freq: 曲线频率,"raw" 为原始频率,"D" 为日频末值
1876
+ :param curve_freq: 曲线频率,默认 "D" 为日频末值,"raw" 为原始频率
1788
1877
  """
1789
1878
  # 延迟导入,避免循环引用和非必要的 Plotly 依赖
1790
1879
  try:
@@ -695,7 +695,7 @@ def _build_benchmark_sections(
695
695
  }
696
696
 
697
697
 
698
- def _build_summary_context(result: Any, curve_freq: str = "raw") -> dict[str, str]:
698
+ def _build_summary_context(result: Any, curve_freq: str = "D") -> dict[str, str]:
699
699
  """Build summary text values for report header."""
700
700
  equity_curve = _resolve_equity_curve(result, curve_freq)
701
701
  start_date = "N/A"
@@ -979,7 +979,7 @@ def _build_chart_html_sections(
979
979
  indicator_symbol: Optional[str] = None,
980
980
  indicator_include_warmup: bool = True,
981
981
  benchmark: Optional[Union[str, pd.Series]] = None,
982
- curve_freq: str = "raw",
982
+ curve_freq: str = "D",
983
983
  ) -> dict[str, str]:
984
984
  """Build chart HTML sections from plot figures."""
985
985
  config = {"responsive": True}
@@ -1179,15 +1179,16 @@ def _build_chart_html_sections(
1179
1179
  else pd.DataFrame()
1180
1180
  )
1181
1181
  top_reasons_df = (
1182
- result.top_reject_reasons(top_n=8)
1183
- if hasattr(result, "top_reject_reasons")
1182
+ result.top_reject_reason_types(top_n=8)
1183
+ if hasattr(result, "top_reject_reason_types")
1184
1184
  else pd.DataFrame()
1185
1185
  )
1186
1186
  if not top_reasons_df.empty:
1187
1187
  top_reasons_view = _rename_table_columns(
1188
1188
  top_reasons_df,
1189
1189
  {
1190
- "reject_reason": "拒单原因 (Reject Reason)",
1190
+ "reject_reason_type": "拒单类型 (Reject Type)",
1191
+ "sample_reject_reason": "示例详情 (Sample Detail)",
1191
1192
  "count": "拒单数 (Count)",
1192
1193
  "ratio": "占比 (Ratio)",
1193
1194
  },
@@ -1948,7 +1949,7 @@ def plot_report(
1948
1949
  indicator_symbol: Optional[str] = None,
1949
1950
  indicator_include_warmup: bool = True,
1950
1951
  benchmark: Optional[Union[str, pd.Series]] = None,
1951
- curve_freq: str = "raw",
1952
+ curve_freq: str = "D",
1952
1953
  ) -> None:
1953
1954
  """
1954
1955
  生成类似 QuantStats 的整合版 HTML 报告 (中文优化版).
@@ -1964,7 +1965,7 @@ def plot_report(
1964
1965
  :param indicator_symbol: 可选标的过滤,仅展示指定标的指标
1965
1966
  :param indicator_include_warmup: 是否在指标报告区块中保留预热点
1966
1967
  :param benchmark: 基准收益序列 (pd.Series) 或基准标识字符串
1967
- :param curve_freq: 曲线频率,"raw" 为原始频率,"D" 为日频末值
1968
+ :param curve_freq: 曲线频率,默认 "D" 为日频末值,"raw" 为原始频率
1968
1969
  """
1969
1970
  if not check_plotly():
1970
1971
  return
@@ -915,6 +915,57 @@ def test_backtest_result_top_reject_reasons_and_lot_size_category() -> None:
915
915
  assert int(risk_df["order_size_limit_reject_count"].sum()) >= 1
916
916
 
917
917
 
918
+ def test_backtest_result_top_reject_reason_types_normalizes_dynamic_details() -> None:
919
+ """Reject type view should merge dynamic messages into stable categories."""
920
+ result = akquant.run_backtest(
921
+ data=_build_regression_bars("REJECT_REASON_TYPE"),
922
+ strategy=SingleBuyStrategy,
923
+ symbols="REJECT_REASON_TYPE",
924
+ fill_policy={"price_basis": "close", "temporal": "same_cycle"},
925
+ lot_size=1,
926
+ show_progress=False,
927
+ )
928
+ result.orders_df = pd.DataFrame(
929
+ {
930
+ "reject_reason": [
931
+ (
932
+ "Risk: Insufficient margin at execution. "
933
+ "Required: 35, Available: -330445.517600"
934
+ ),
935
+ (
936
+ "Risk: Insufficient margin at execution. "
937
+ "Required: 35, Available: -310706.591600"
938
+ ),
939
+ "Order error: Risk: Daily loss 5.46% exceeds limit 5.00%",
940
+ "Order error: Risk: Daily loss 8.79% exceeds limit 5.00%",
941
+ "",
942
+ ],
943
+ "status": ["Rejected", "Rejected", "Rejected", "Rejected", "Rejected"],
944
+ }
945
+ )
946
+
947
+ top_reason_types = result.top_reject_reason_types(top_n=5)
948
+
949
+ assert not top_reason_types.empty
950
+ assert "reject_reason_type" in top_reason_types.columns
951
+ assert "sample_reject_reason" in top_reason_types.columns
952
+ assert "count" in top_reason_types.columns
953
+ assert "ratio" in top_reason_types.columns
954
+ counts = dict(
955
+ zip(
956
+ top_reason_types["reject_reason_type"].astype(str),
957
+ top_reason_types["count"].astype(int),
958
+ )
959
+ )
960
+ assert counts["Insufficient Margin"] == 2
961
+ assert counts["Daily Loss Limit"] == 2
962
+ sample_detail = top_reason_types.loc[
963
+ top_reason_types["reject_reason_type"].astype(str) == "Insufficient Margin",
964
+ "sample_reject_reason",
965
+ ].iloc[0]
966
+ assert "Required: 35" in str(sample_detail)
967
+
968
+
918
969
  def test_policy_resolver_next_close_same_cycle_sets_timer_same_cycle() -> None:
919
970
  """Close + bar_offset=1 + same_cycle should resolve timer policy."""
920
971
  resolved = backtest_engine._resolve_execution_policy(
@@ -1,10 +1,12 @@
1
1
  import importlib.util
2
+ import inspect
2
3
  from pathlib import Path
3
4
  from typing import cast
4
5
 
5
6
  import pandas as pd
6
7
  import pytest
7
8
  from akquant import Bar, Strategy, run_backtest
9
+ from akquant.backtest.result import BacktestResult
8
10
  from akquant.config import RiskConfig
9
11
  from akquant.plot import (
10
12
  plot_dashboard,
@@ -716,6 +718,12 @@ def test_report_accepts_curve_freq_daily(tmp_path: Path) -> None:
716
718
  assert report_path.exists()
717
719
 
718
720
 
721
+ def test_report_defaults_curve_freq_to_daily() -> None:
722
+ """Report API should default to daily curve frequency for lighter HTML."""
723
+ default_value = inspect.signature(BacktestResult.report)
724
+ assert default_value.parameters["curve_freq"].default == "D"
725
+
726
+
719
727
  def test_report_rejects_invalid_curve_freq(tmp_path: Path) -> None:
720
728
  """Report generation should reject unsupported curve frequency values."""
721
729
  _skip_if_no_plotly()
@@ -737,6 +745,45 @@ def test_report_rejects_invalid_curve_freq(tmp_path: Path) -> None:
737
745
  result.report(filename=str(report_path), show=False, curve_freq="W")
738
746
 
739
747
 
748
+ def test_report_displays_normalized_reject_reason_types(tmp_path: Path) -> None:
749
+ """Report HTML should show reject types and sample details separately."""
750
+ _skip_if_no_plotly()
751
+ result = run_backtest(
752
+ data=_build_intraday_data(),
753
+ strategy=NoTradeStrategy,
754
+ symbols="TEST",
755
+ initial_cash=200000.0,
756
+ commission_rate=0.0,
757
+ stamp_tax_rate=0.0,
758
+ transfer_fee_rate=0.0,
759
+ min_commission=0.0,
760
+ fill_policy={"price_basis": "close", "temporal": "same_cycle"},
761
+ lot_size=1,
762
+ show_progress=False,
763
+ )
764
+ result.orders_df = pd.DataFrame(
765
+ {
766
+ "reject_reason": [
767
+ (
768
+ "Risk: Insufficient margin at execution. "
769
+ "Required: 35, Available: -330445.517600"
770
+ ),
771
+ (
772
+ "Risk: Insufficient margin at execution. "
773
+ "Required: 35, Available: -310706.591600"
774
+ ),
775
+ ],
776
+ "status": ["Rejected", "Rejected"],
777
+ }
778
+ )
779
+ report_path = tmp_path / "report_reject_reason_types.html"
780
+ result.report(filename=str(report_path), show=False)
781
+ html = report_path.read_text(encoding="utf-8")
782
+ assert "拒单类型 (Reject Type)" in html
783
+ assert "示例详情 (Sample Detail)" in html
784
+ assert "Insufficient Margin" in html
785
+
786
+
740
787
  def test_report_contains_forced_liquidation_audit_section(tmp_path: Path) -> None:
741
788
  """Report HTML should include forced liquidation audit section and entries."""
742
789
  _skip_if_no_plotly()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes