powerquant-cli 0.2.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (355) hide show
  1. powerquant_cli-0.2.6.dist-info/METADATA +62 -0
  2. powerquant_cli-0.2.6.dist-info/RECORD +355 -0
  3. powerquant_cli-0.2.6.dist-info/WHEEL +4 -0
  4. powerquant_cli-0.2.6.dist-info/entry_points.txt +2 -0
  5. powerquant_cli-0.2.6.dist-info/licenses/LICENSE +36 -0
  6. powerquant_cli-0.2.6.dist-info/licenses/licenses/LICENSE.vnpy +21 -0
  7. pqdata/__init__.py +6 -0
  8. pqdata/client.py +389 -0
  9. pqdata/download.py +60 -0
  10. pqdata/exceptions.py +14 -0
  11. pqdata/schema/__init__.py +1 -0
  12. pqdata/schema/adjustment_schema.py +67 -0
  13. pqdata/schema/bar_content_schema.py +24 -0
  14. pqdata/schema/bar_schema.py +56 -0
  15. pqdata/schema/corporate_action_schema.py +46 -0
  16. pqdata/schema/history_schema.py +61 -0
  17. pqdata/schema/pit_daily_window.py +16 -0
  18. pqdata/schema/query_schema.py +53 -0
  19. pqdata/schema/quote_schema.py +73 -0
  20. pqdata/schema/reference_schema.py +48 -0
  21. pqdata/schema/reliability_schema.py +152 -0
  22. quant_cli/__init__.py +0 -0
  23. quant_cli/api.py +39 -0
  24. quant_cli/app/__init__.py +0 -0
  25. quant_cli/app/backtest/__init__.py +0 -0
  26. quant_cli/app/backtest/cli/__init__.py +0 -0
  27. quant_cli/app/backtest/cli/local_backtest_cli.py +72 -0
  28. quant_cli/app/backtest/local_backtest_dependency.py +10 -0
  29. quant_cli/app/backtest/local_backtest_schema.py +49 -0
  30. quant_cli/app/backtest/repository/__init__.py +0 -0
  31. quant_cli/app/backtest/repository/backtest_local_repository.py +67 -0
  32. quant_cli/app/backtest/service/__init__.py +0 -0
  33. quant_cli/app/backtest/service/local_backtest_service.py +271 -0
  34. quant_cli/app/data/__init__.py +0 -0
  35. quant_cli/app/data/cli/__init__.py +0 -0
  36. quant_cli/app/data/cli/data_cli.py +78 -0
  37. quant_cli/app/data/data_dependency.py +35 -0
  38. quant_cli/app/data/repository/__init__.py +0 -0
  39. quant_cli/app/data/repository/parquet_repository.py +124 -0
  40. quant_cli/app/data/schema/__init__.py +0 -0
  41. quant_cli/app/data/schema/dataset_audit_schema.py +37 -0
  42. quant_cli/app/data/schema/dataset_request_schema.py +28 -0
  43. quant_cli/app/data/schema/parquet_file_schema.py +17 -0
  44. quant_cli/app/data/service/__init__.py +0 -0
  45. quant_cli/app/data/service/bar_cache_service.py +287 -0
  46. quant_cli/app/data/service/dataset_audit_service.py +137 -0
  47. quant_cli/app/data/service/dataset_load_service.py +115 -0
  48. quant_cli/app/data/service/dataset_prepare_service.py +187 -0
  49. quant_cli/app/factor/__init__.py +0 -0
  50. quant_cli/app/factor/cli/__init__.py +0 -0
  51. quant_cli/app/factor/cli/factor_definition_cli.py +81 -0
  52. quant_cli/app/factor/cli/local_factor_cli.py +102 -0
  53. quant_cli/app/factor/cli/local_selection_cli.py +58 -0
  54. quant_cli/app/factor/interface/__init__.py +0 -0
  55. quant_cli/app/factor/interface/local_selection_store.py +12 -0
  56. quant_cli/app/factor/local_factor_dependency.py +38 -0
  57. quant_cli/app/factor/repository/__init__.py +0 -0
  58. quant_cli/app/factor/repository/factor_local_repository.py +154 -0
  59. quant_cli/app/factor/repository/selection_local_repository.py +67 -0
  60. quant_cli/app/factor/schema/local_selection_schema.py +56 -0
  61. quant_cli/app/factor/service/__init__.py +0 -0
  62. quant_cli/app/factor/service/factor_data_prepare_service.py +181 -0
  63. quant_cli/app/factor/service/local_factor_query_service.py +146 -0
  64. quant_cli/app/factor/service/local_factor_service.py +120 -0
  65. quant_cli/app/factor/service/local_selection_service.py +139 -0
  66. quant_cli/app/job/__init__.py +0 -0
  67. quant_cli/app/job/cli/__init__.py +0 -0
  68. quant_cli/app/job/cli/local_job_cli.py +69 -0
  69. quant_cli/app/job/schema/__init__.py +0 -0
  70. quant_cli/app/job/schema/local_job_schema.py +11 -0
  71. quant_cli/app/job/service/__init__.py +0 -0
  72. quant_cli/app/job/service/local_job_service.py +60 -0
  73. quant_cli/app/quant_cli.py +49 -0
  74. quant_cli/app/research/__init__.py +0 -0
  75. quant_cli/app/research/cli/__init__.py +0 -0
  76. quant_cli/app/research/cli/local_research_cli.py +93 -0
  77. quant_cli/app/research/local_research_dependency.py +10 -0
  78. quant_cli/app/research/repository/__init__.py +0 -0
  79. quant_cli/app/research/repository/research_local_repository.py +67 -0
  80. quant_cli/app/research/schema/__init__.py +0 -0
  81. quant_cli/app/research/schema/local_research_schema.py +26 -0
  82. quant_cli/app/research/service/__init__.py +0 -0
  83. quant_cli/app/research/service/local_research_execution_service.py +105 -0
  84. quant_cli/app/research/service/local_research_service.py +101 -0
  85. quant_cli/app/strategy/__init__.py +0 -0
  86. quant_cli/app/strategy/cli/__init__.py +0 -0
  87. quant_cli/app/strategy/cli/strategy_cli.py +104 -0
  88. quant_cli/common/__init__.py +0 -0
  89. quant_cli/common/constants.py +7 -0
  90. quant_cli/common/database/__init__.py +0 -0
  91. quant_cli/common/database/duckdb_connection.py +30 -0
  92. quant_cli/common/http/__init__.py +0 -0
  93. quant_cli/common/http/definition_client.py +54 -0
  94. quant_cli/common/utils/__init__.py +0 -0
  95. quant_cli/common/utils/cli_utils.py +37 -0
  96. quant_cli/common/utils/platform_utils.py +11 -0
  97. quant_cli/common/utils/runtime_environment.py +12 -0
  98. quant_cli/examples/cached_factor_screen.py +165 -0
  99. quant_cli/examples/factors/ma_close_10.py +10 -0
  100. quant_cli/examples/factors/max_drawdown_20d.py +18 -0
  101. quant_cli/examples/factors/momentum_20d.py +13 -0
  102. quant_cli/examples/factors/multi_intraday_screen.py +16 -0
  103. quant_cli/examples/factors/risk_adjusted_momentum_20d.py +18 -0
  104. quant_cli/examples/factors/volume_ratio_5d.py +14 -0
  105. quant_cli/examples/factors/volume_weighted_close_pressure.py +14 -0
  106. quant_cli/examples/full_market_screen.py +189 -0
  107. quant_cli/examples/local_quant_validation.py +196 -0
  108. quant_cli/examples/published_definition_validation.py +219 -0
  109. quant_cli/examples/research/factor_pit_coverage.py +87 -0
  110. quant_cli/examples/research/ipo_first_day.py +348 -0
  111. quant_cli/examples/selection/README.md +59 -0
  112. quant_cli/examples/selection/backtest.json +18 -0
  113. quant_cli/examples/selection/buy_hold.py +7 -0
  114. quant_cli/examples/selection/compute.json +15 -0
  115. quant_cli/examples/selection/prepare.json +13 -0
  116. quant_cli/examples/selection/select.json +44 -0
  117. quant_cli/examples/strategies/bar_roundtrip.py +12 -0
  118. quant_cli/examples/strategies/buy_and_hold.py +11 -0
  119. quant_cli/examples/strategies/contrarian_timing.py +14 -0
  120. quant_cli/examples/strategies/factor_gate_vwap.py +22 -0
  121. quant_cli/examples/strategies/ipo_next_day_vwap.py +31 -0
  122. quant_cli/examples/strategies/momentum_timing.py +14 -0
  123. quant_cli/examples/strategies/monthly_equal_weight.py +19 -0
  124. quant_cli/examples/strategies/session_roundtrip.py +16 -0
  125. quant_cli/examples/strategies/trend_drawdown_guard.py +22 -0
  126. quant_cli/examples/strategies/weekly_risk_adjusted_rotation.py +61 -0
  127. quant_cli/examples/unified_snapshot_validation.py +260 -0
  128. quant_core/__init__.py +0 -0
  129. quant_core/app/SPEC.md +18 -0
  130. quant_core/app/__init__.py +0 -0
  131. quant_core/app/backtest/SPEC.md +65 -0
  132. quant_core/app/backtest/__init__.py +1 -0
  133. quant_core/app/backtest/backtest_input_schema.py +20 -0
  134. quant_core/app/backtest/backtest_run.py +393 -0
  135. quant_core/app/backtest/data_guard.py +77 -0
  136. quant_core/app/backtest/historical_clock.py +26 -0
  137. quant_core/app/backtest/legacy_result_schema.py +34 -0
  138. quant_core/app/backtest/metrics.py +194 -0
  139. quant_core/app/backtest/performance_report.py +61 -0
  140. quant_core/app/backtest/report_schema.py +64 -0
  141. quant_core/app/backtest/schema.py +477 -0
  142. quant_core/app/backtest/service/__init__.py +0 -0
  143. quant_core/app/backtest/service/backtest_execution_service.py +114 -0
  144. quant_core/app/data/__init__.py +0 -0
  145. quant_core/app/data/constants.py +284 -0
  146. quant_core/app/data/domain/__init__.py +0 -0
  147. quant_core/app/data/domain/trading_quantity_value.py +57 -0
  148. quant_core/app/data/exceptions.py +95 -0
  149. quant_core/app/data/interface/__init__.py +0 -0
  150. quant_core/app/data/interface/adjustment_factor_query.py +21 -0
  151. quant_core/app/data/interface/market_data_query.py +71 -0
  152. quant_core/app/data/interface/market_data_verification.py +20 -0
  153. quant_core/app/data/interface/market_event_source.py +11 -0
  154. quant_core/app/data/interface/market_revision_query.py +8 -0
  155. quant_core/app/data/interface/market_runtime_repository.py +44 -0
  156. quant_core/app/data/interface/market_time_slice_source.py +11 -0
  157. quant_core/app/data/repository/__init__.py +0 -0
  158. quant_core/app/data/schema/__init__.py +1 -0
  159. quant_core/app/data/schema/adjustment_schema.py +67 -0
  160. quant_core/app/data/schema/corporate_action_schema.py +46 -0
  161. quant_core/app/data/schema/event_schema.py +506 -0
  162. quant_core/app/data/schema/exchange_operating_state.py +37 -0
  163. quant_core/app/data/schema/exchange_state_schema.py +106 -0
  164. quant_core/app/data/schema/history_schema.py +48 -0
  165. quant_core/app/data/schema/instrument_identity.py +69 -0
  166. quant_core/app/data/schema/market_schema.py +128 -0
  167. quant_core/app/data/schema/pit_daily_window.py +16 -0
  168. quant_core/app/data/schema/quote_schema.py +73 -0
  169. quant_core/app/data/schema/reliability_schema.py +152 -0
  170. quant_core/app/data/schema/snapshot_schema.py +82 -0
  171. quant_core/app/data/schema/trading_state_schema.py +211 -0
  172. quant_core/app/data/service/__init__.py +0 -0
  173. quant_core/app/data/service/calendar_coverage_service.py +63 -0
  174. quant_core/app/data/service/prepared_data_verification_service.py +40 -0
  175. quant_core/app/data/service/prepared_market_service.py +189 -0
  176. quant_core/app/data/service/price_adjustment_service.py +235 -0
  177. quant_core/app/factor/LICENSE.vnpy +21 -0
  178. quant_core/app/factor/__init__.py +13 -0
  179. quant_core/app/factor/builtin/__init__.py +0 -0
  180. quant_core/app/factor/builtin/alpha101_recipe.py +1095 -0
  181. quant_core/app/factor/builtin/alpha158_recipe.py +1284 -0
  182. quant_core/app/factor/builtin/factor_recipe_catalog.py +100 -0
  183. quant_core/app/factor/computation/__init__.py +0 -0
  184. quant_core/app/factor/computation/factor_batch_evaluator.py +141 -0
  185. quant_core/app/factor/computation/factor_expression.py +106 -0
  186. quant_core/app/factor/computation/factor_source_loader.py +24 -0
  187. quant_core/app/factor/computation/operators/__init__.py +0 -0
  188. quant_core/app/factor/computation/operators/arithmetic_operator.py +182 -0
  189. quant_core/app/factor/computation/operators/cross_section_operator.py +66 -0
  190. quant_core/app/factor/computation/operators/time_series_operator.py +342 -0
  191. quant_core/app/factor/computation/panel_evaluator.py +59 -0
  192. quant_core/app/factor/computation/panel_expression.py +193 -0
  193. quant_core/app/factor/computation/python_factor_executor.py +87 -0
  194. quant_core/app/factor/computation/universe_filter.py +25 -0
  195. quant_core/app/factor/constants.py +114 -0
  196. quant_core/app/factor/exceptions.py +35 -0
  197. quant_core/app/factor/factor_dependency.py +65 -0
  198. quant_core/app/factor/interface/__init__.py +0 -0
  199. quant_core/app/factor/interface/factor_compute.py +12 -0
  200. quant_core/app/factor/interface/factor_execution.py +15 -0
  201. quant_core/app/factor/interface/factor_local_data.py +42 -0
  202. quant_core/app/factor/interface/factor_panel_compute.py +18 -0
  203. quant_core/app/factor/interface/factor_panel_input.py +12 -0
  204. quant_core/app/factor/interface/factor_query_store.py +39 -0
  205. quant_core/app/factor/interface/public/__init__.py +0 -0
  206. quant_core/app/factor/interface/public/factor_diagnostics.py +18 -0
  207. quant_core/app/factor/interface/public/factor_exposure_query.py +12 -0
  208. quant_core/app/factor/interface/public/factor_local.py +15 -0
  209. quant_core/app/factor/interface/public/factor_query.py +57 -0
  210. quant_core/app/factor/interface/public/factor_selection.py +20 -0
  211. quant_core/app/factor/model/__init__.py +0 -0
  212. quant_core/app/factor/repository/__init__.py +0 -0
  213. quant_core/app/factor/schema/__init__.py +1 -0
  214. quant_core/app/factor/schema/diagnostic_types.py +42 -0
  215. quant_core/app/factor/schema/factor_artifact_schema.py +36 -0
  216. quant_core/app/factor/schema/factor_computation_schema.py +102 -0
  217. quant_core/app/factor/schema/factor_compute_request.py +24 -0
  218. quant_core/app/factor/schema/factor_contract.py +257 -0
  219. quant_core/app/factor/schema/factor_input_schema.py +32 -0
  220. quant_core/app/factor/schema/factor_panel.py +65 -0
  221. quant_core/app/factor/schema/factor_publication_schema.py +41 -0
  222. quant_core/app/factor/schema/factor_query_result_schema.py +12 -0
  223. quant_core/app/factor/schema/factor_result_schema.py +6 -0
  224. quant_core/app/factor/schema/local_factor_schema.py +42 -0
  225. quant_core/app/factor/schema/panel_policy.py +13 -0
  226. quant_core/app/factor/schema/selection_report.py +116 -0
  227. quant_core/app/factor/schema/selection_types.py +135 -0
  228. quant_core/app/factor/service/__init__.py +1 -0
  229. quant_core/app/factor/service/factor_compute_service.py +140 -0
  230. quant_core/app/factor/service/factor_diagnostic_runner.py +134 -0
  231. quant_core/app/factor/service/factor_diagnostics_service.py +140 -0
  232. quant_core/app/factor/service/factor_exposure_service.py +24 -0
  233. quant_core/app/factor/service/factor_input_service.py +258 -0
  234. quant_core/app/factor/service/factor_local_execution_service.py +51 -0
  235. quant_core/app/factor/service/factor_panel_service.py +86 -0
  236. quant_core/app/factor/service/factor_runtime_service.py +306 -0
  237. quant_core/app/factor/service/factor_selection_runner.py +88 -0
  238. quant_core/app/factor/service/published_factor_execution_service.py +160 -0
  239. quant_core/app/factor/service/selection_service.py +234 -0
  240. quant_core/app/factor/visibility.py +22 -0
  241. quant_core/app/opportunity/SPEC.md +45 -0
  242. quant_core/app/opportunity/__init__.py +1 -0
  243. quant_core/app/order_execution/SPEC.md +64 -0
  244. quant_core/app/order_execution/__init__.py +1 -0
  245. quant_core/app/order_execution/bar_matcher.py +55 -0
  246. quant_core/app/order_execution/constants.py +142 -0
  247. quant_core/app/order_execution/domain/__init__.py +45 -0
  248. quant_core/app/order_execution/domain/execution_batch.py +108 -0
  249. quant_core/app/order_execution/domain/order_entity.py +197 -0
  250. quant_core/app/order_execution/domain/order_event.py +87 -0
  251. quant_core/app/order_execution/domain/order_policy.py +29 -0
  252. quant_core/app/order_execution/domain/order_value.py +142 -0
  253. quant_core/app/order_execution/fee_model.py +60 -0
  254. quant_core/app/order_execution/interface/__init__.py +0 -0
  255. quant_core/app/order_execution/interface/order_account.py +10 -0
  256. quant_core/app/order_execution/interface/order_trading_rules.py +10 -0
  257. quant_core/app/order_execution/interface/public/__init__.py +0 -0
  258. quant_core/app/order_execution/interface/public/execution_account.py +53 -0
  259. quant_core/app/order_execution/interface/public/order_events.py +19 -0
  260. quant_core/app/order_execution/interface/public/order_execution.py +107 -0
  261. quant_core/app/order_execution/interface/public/order_runtime.py +30 -0
  262. quant_core/app/order_execution/interface/public/order_submission.py +17 -0
  263. quant_core/app/order_execution/order_event_bus.py +28 -0
  264. quant_core/app/order_execution/order_execution_dependency.py +48 -0
  265. quant_core/app/order_execution/order_submission_service.py +301 -0
  266. quant_core/app/order_execution/schema/__init__.py +0 -0
  267. quant_core/app/order_execution/schema/order_request_schema.py +88 -0
  268. quant_core/app/order_execution/simulation_broker.py +883 -0
  269. quant_core/app/order_execution/slippage_model.py +40 -0
  270. quant_core/app/order_execution/tradability_policy.py +174 -0
  271. quant_core/app/order_execution/validators.py +40 -0
  272. quant_core/app/portfolio/SPEC.md +69 -0
  273. quant_core/app/portfolio/__init__.py +0 -0
  274. quant_core/app/portfolio/domain/__init__.py +32 -0
  275. quant_core/app/portfolio/domain/entitlement_entity.py +45 -0
  276. quant_core/app/portfolio/domain/portfolio_entity.py +511 -0
  277. quant_core/app/portfolio/domain/portfolio_event.py +59 -0
  278. quant_core/app/portfolio/domain/portfolio_value.py +21 -0
  279. quant_core/app/portfolio/domain/position_entity.py +165 -0
  280. quant_core/app/portfolio/domain/reservation_entity.py +69 -0
  281. quant_core/app/portfolio/interface/__init__.py +0 -0
  282. quant_core/app/portfolio/interface/public/__init__.py +0 -0
  283. quant_core/app/portfolio/interface/public/portfolio.py +77 -0
  284. quant_core/app/portfolio/interface/public/simulation_account.py +16 -0
  285. quant_core/app/portfolio/ledger_schema.py +130 -0
  286. quant_core/app/portfolio/order_account_listener.py +36 -0
  287. quant_core/app/portfolio/portfolio_dependency.py +21 -0
  288. quant_core/app/portfolio/portfolio_schema.py +204 -0
  289. quant_core/app/portfolio/simulated_portfolio.py +427 -0
  290. quant_core/app/research/SPEC.md +57 -0
  291. quant_core/app/research/__init__.py +0 -0
  292. quant_core/app/research/adapter/__init__.py +0 -0
  293. quant_core/app/research/adapter/market_label_query.py +84 -0
  294. quant_core/app/research/interface/__init__.py +0 -0
  295. quant_core/app/research/interface/research_dataset.py +47 -0
  296. quant_core/app/research/interface/research_evaluation.py +19 -0
  297. quant_core/app/research/schema/__init__.py +0 -0
  298. quant_core/app/research/schema/comparison_schema.py +12 -0
  299. quant_core/app/research/schema/dataset_schema.py +112 -0
  300. quant_core/app/research/schema/research_schema.py +120 -0
  301. quant_core/app/research/service/__init__.py +0 -0
  302. quant_core/app/research/service/research_dataset_service.py +80 -0
  303. quant_core/app/research/service/research_evaluation_service.py +56 -0
  304. quant_core/app/research/service/research_service.py +171 -0
  305. quant_core/app/strategy/SPEC.md +215 -0
  306. quant_core/app/strategy/__init__.py +1 -0
  307. quant_core/app/strategy/constants.py +87 -0
  308. quant_core/app/strategy/exceptions.py +32 -0
  309. quant_core/app/strategy/interface/__init__.py +0 -0
  310. quant_core/app/strategy/interface/public/__init__.py +0 -0
  311. quant_core/app/strategy/interface/public/portfolio_construction.py +19 -0
  312. quant_core/app/strategy/interface/public/strategy.py +30 -0
  313. quant_core/app/strategy/interface/public/strategy_market_query.py +53 -0
  314. quant_core/app/strategy/interface/public/strategy_portfolio_reader.py +33 -0
  315. quant_core/app/strategy/interface/strategy_factor_reader.py +19 -0
  316. quant_core/app/strategy/interface/strategy_order_reader.py +14 -0
  317. quant_core/app/strategy/schema/__init__.py +0 -0
  318. quant_core/app/strategy/schema/portfolio_schema.py +28 -0
  319. quant_core/app/strategy/schema/portfolio_target.py +70 -0
  320. quant_core/app/strategy/schema/python_strategy_schema.py +94 -0
  321. quant_core/app/strategy/schema/screener_schema.py +51 -0
  322. quant_core/app/strategy/schema/signal_schema.py +33 -0
  323. quant_core/app/strategy/schema/strategy_publication_schema.py +32 -0
  324. quant_core/app/strategy/schema/strategy_schema.py +96 -0
  325. quant_core/app/strategy/service/__init__.py +0 -0
  326. quant_core/app/strategy/service/factor_top_n_strategy.py +103 -0
  327. quant_core/app/strategy/service/portfolio_construction_service.py +142 -0
  328. quant_core/app/strategy/service/python_strategy_service.py +65 -0
  329. quant_core/app/strategy/service/screener_service.py +77 -0
  330. quant_core/app/strategy/service/store_factor_reader.py +120 -0
  331. quant_core/app/strategy/service/strategy_market_view.py +120 -0
  332. quant_core/app/strategy/service/strategy_runtime_service.py +319 -0
  333. quant_core/app/strategy/service/strategy_scheduler.py +50 -0
  334. quant_core/app/strategy/strategies/__init__.py +7 -0
  335. quant_core/app/strategy/strategies/momentum_volume_breakout.py +157 -0
  336. quant_core/app/strategy/strategy_context.py +316 -0
  337. quant_core/app/strategy/strategy_dependency.py +101 -0
  338. quant_core/app/trading_runtime/SPEC.md +70 -0
  339. quant_core/app/trading_runtime/__init__.py +1 -0
  340. quant_core/app/trading_runtime/domain/__init__.py +0 -0
  341. quant_core/app/trading_runtime/replay/__init__.py +0 -0
  342. quant_core/app/trading_runtime/replay/daily_state_expand.py +49 -0
  343. quant_core/app/trading_runtime/replay/exchange_state_resolver.py +90 -0
  344. quant_core/app/trading_runtime/replay/market_runtime_service.py +573 -0
  345. quant_core/app/trading_runtime/replay/market_state_resolver.py +150 -0
  346. quant_core/app/trading_runtime/runtime_ports.py +64 -0
  347. quant_core/app/trading_runtime/runtime_schema.py +129 -0
  348. quant_core/app/trading_runtime/runtime_session.py +361 -0
  349. quant_core/app/trading_runtime/strategy_portfolio_adapter.py +58 -0
  350. quant_core/app/trading_runtime/trading_rule_book.py +37 -0
  351. quant_core/app/trading_runtime/trading_rule_query.py +12 -0
  352. quant_core/common/__init__.py +0 -0
  353. quant_core/common/exceptions/__init__.py +0 -0
  354. quant_core/common/exceptions/base.py +89 -0
  355. quant_core/common/local_run.py +45 -0
@@ -0,0 +1,194 @@
1
+ from typing import TypedDict
2
+
3
+ """Backtest Metrics - 纯 Decimal 指标计算(T7)
4
+
5
+ 口径 SSOT:T7 Task Confirmed Decisions(2026-09-05 用户确认)。全部函数
6
+ 只消费公开的 EquityCurve / BacktestConfig 标量,不读取 Runtime / Portfolio
7
+ 私有状态,不复制 Portfolio 记账逻辑。
8
+
9
+ Decimal 处理:
10
+ - 全程 Decimal(含幂与开方:``Decimal ** Decimal`` / ``Decimal.sqrt()``,
11
+ 按当前 decimal context 精度求正确舍入结果);
12
+ - 不把 float 引入领域结果,不调用 ``quantize``。
13
+
14
+ 公式(与 T7 Task 逐字对应):
15
+ - daily_risk_free_return = (1 + annual_risk_free_rate) ** (1/tdpy) - 1
16
+ (几何无风险转换,与 annualized_return 的幂口径一致)
17
+ - total_return = ending_equity / initial_cash - 1
18
+ - max_drawdown = max((peak - v) / peak);无回撤为 0
19
+ - annualized_return = (ending/initial) ** (tdpy / n_days) - 1;n_days < 2 → None
20
+ - sharpe_ratio = mean(daily_returns - daily_rf) / sample_stddev(daily_returns)
21
+ * sqrt(tdpy);日收益 < 2 个或样本标准差为 0 → None
22
+ - gross_turnover_rate = Σ abs(fill.price × fill.quantity) / 平均日末组合净值;
23
+ 空曲线或平均日末净值为 0 → None,费用不进入成交金额
24
+ """
25
+
26
+ from decimal import Decimal
27
+
28
+ from quant_core.app.backtest.schema import BacktestMetrics, EquityCurve, EquityPoint
29
+ from quant_core.app.order_execution.domain.order_event import Fill
30
+ from quant_core.app.portfolio.ledger_schema import ClosedTrade
31
+
32
+ _ONE = Decimal("1")
33
+
34
+
35
+ def daily_equity_points(curve: EquityCurve) -> tuple[EquityPoint, ...]:
36
+ """日频采样:每个交易日期取最后一个 Equity Curve 点(时间严格递增)"""
37
+ last_by_day: dict[str, EquityPoint] = {}
38
+ for point in curve.points:
39
+ last_by_day[point.time.date().isoformat()] = point # 时间递增 → 后写即当日最后
40
+ return tuple(sorted(last_by_day.values(), key=lambda p: p.time))
41
+
42
+
43
+ def daily_risk_free_return(
44
+ annual_risk_free_rate: Decimal, trading_days_per_year: Decimal
45
+ ) -> Decimal:
46
+ """年化无风险收益率的几何日频转换(明确公式,测试覆盖)"""
47
+ return (_ONE + annual_risk_free_rate) ** (_ONE / trading_days_per_year) - _ONE
48
+
49
+
50
+ def daily_returns(curve: EquityCurve, initial_cash: Decimal) -> tuple[Decimal | None, ...]:
51
+ """日频收益序列:首日相对 initial_cash,其后为相邻交易日收盘权益之比减一
52
+
53
+ 前一日权益为 0 时相邻比无定义 → 该日收益为 None(禁止 epsilon /
54
+ 伪造收益率;首日相对 initial_cash > 0 恒可定义,权益归零即 -1)。
55
+ """
56
+ points = daily_equity_points(curve)
57
+ returns: list[Decimal | None] = []
58
+ previous = initial_cash
59
+ for point in points:
60
+ if previous == 0:
61
+ returns.append(None)
62
+ else:
63
+ returns.append(point.total_value / previous - _ONE)
64
+ previous = point.total_value
65
+ return tuple(returns)
66
+
67
+
68
+ def _sample_stddev(values: tuple[Decimal, ...]) -> Decimal:
69
+ """样本标准差(n - 1 分母;调用方保证 n >= 2)"""
70
+ n = Decimal(len(values))
71
+ mean = sum(values, Decimal("0")) / n
72
+ variance = sum(((v - mean) ** 2 for v in values), Decimal("0")) / (n - _ONE)
73
+ return variance.sqrt()
74
+
75
+
76
+ def compute_max_drawdown(curve: EquityCurve) -> Decimal:
77
+ """相对历史峰值的最大跌幅(非负;无回撤为 0)"""
78
+ max_dd = Decimal("0")
79
+ peak: Decimal | None = None
80
+ for point in curve.points:
81
+ value = point.total_value
82
+ if peak is None or value > peak:
83
+ peak = value
84
+ elif peak > 0:
85
+ drawdown = (peak - value) / peak
86
+ if drawdown > max_dd:
87
+ max_dd = drawdown
88
+ return max_dd
89
+
90
+
91
+ def compute_gross_turnover_rate(curve: EquityCurve, fills: tuple[Fill, ...]) -> Decimal | None:
92
+ """成交绝对金额合计除以平均日末组合净值。
93
+
94
+ 成交金额不含费用;分钟曲线先按交易日取最后一点,避免因 Bar 数量不同
95
+ 改变分母权重。空曲线或平均日末净值为零时不可计算。
96
+ """
97
+ day_points = daily_equity_points(curve)
98
+ if not day_points:
99
+ return None
100
+ average_value = sum((point.total_value for point in day_points), Decimal("0")) / Decimal(
101
+ len(day_points)
102
+ )
103
+ if average_value == 0:
104
+ return None
105
+ gross_notional = sum((fill.price * Decimal(fill.quantity) for fill in fills), Decimal("0"))
106
+ return gross_notional / average_value
107
+
108
+
109
+ def compute_metrics(
110
+ curve: EquityCurve,
111
+ initial_cash: Decimal,
112
+ fill_count: int,
113
+ trading_days_per_year: Decimal,
114
+ annual_risk_free_rate: Decimal,
115
+ closed_trades: tuple[ClosedTrade, ...] | None = None,
116
+ fills: tuple[Fill, ...] = (),
117
+ ) -> BacktestMetrics:
118
+ """由已成功提交的权益曲线计算基础指标(口径见模块 docstring)"""
119
+ ending = curve.last_value
120
+ total_return = None if ending is None else ending / initial_cash - _ONE
121
+
122
+ day_points = daily_equity_points(curve)
123
+ n_days = len(day_points)
124
+ annualized_return: Decimal | None = None
125
+ sharpe_ratio: Decimal | None = None
126
+ if ending is not None and n_days >= 2:
127
+ annualized_return = (ending / initial_cash) ** (
128
+ trading_days_per_year / Decimal(n_days)
129
+ ) - _ONE
130
+
131
+ returns = daily_returns(curve, initial_cash)
132
+ defined = [r for r in returns if r is not None]
133
+ # 存在无定义日收益(前一日权益为 0)→ Sharpe 不可计算,返回 None
134
+ if len(returns) >= 2 and len(defined) == len(returns):
135
+ stddev = _sample_stddev(tuple(defined))
136
+ if stddev != 0:
137
+ daily_rf = daily_risk_free_return(annual_risk_free_rate, trading_days_per_year)
138
+ excess_mean = sum((r - daily_rf for r in defined), Decimal("0")) / Decimal(
139
+ len(defined)
140
+ )
141
+ sharpe_ratio = excess_mean / stddev * trading_days_per_year.sqrt()
142
+
143
+ trade_metrics = _compute_trade_metrics(closed_trades)
144
+ return BacktestMetrics(
145
+ total_return=total_return,
146
+ annualized_return=annualized_return,
147
+ max_drawdown=compute_max_drawdown(curve),
148
+ sharpe_ratio=sharpe_ratio,
149
+ fill_count=fill_count,
150
+ gross_turnover_rate=compute_gross_turnover_rate(curve, fills),
151
+ **trade_metrics,
152
+ )
153
+
154
+
155
+ class _TradeMetrics(TypedDict):
156
+ trade_count: int | None
157
+ win_rate: Decimal | None
158
+ profit_loss_ratio: Decimal | None
159
+ average_holding_days: Decimal | None
160
+
161
+
162
+ def _compute_trade_metrics(closed_trades: tuple[ClosedTrade, ...] | None) -> _TradeMetrics:
163
+ if closed_trades is None:
164
+ return {
165
+ "trade_count": None,
166
+ "win_rate": None,
167
+ "profit_loss_ratio": None,
168
+ "average_holding_days": None,
169
+ }
170
+ count = len(closed_trades)
171
+ if count == 0:
172
+ return {
173
+ "trade_count": 0,
174
+ "win_rate": None,
175
+ "profit_loss_ratio": None,
176
+ "average_holding_days": None,
177
+ }
178
+ wins = tuple(trade.realized_pnl for trade in closed_trades if trade.realized_pnl > 0)
179
+ losses = tuple(-trade.realized_pnl for trade in closed_trades if trade.realized_pnl < 0)
180
+ average_win = sum(wins, Decimal("0")) / Decimal(len(wins)) if wins else None
181
+ average_loss = sum(losses, Decimal("0")) / Decimal(len(losses)) if losses else None
182
+ return {
183
+ "trade_count": count,
184
+ "win_rate": Decimal(len(wins)) / Decimal(count),
185
+ "profit_loss_ratio": (
186
+ average_win / average_loss
187
+ if average_win is not None and average_loss not in (None, Decimal("0"))
188
+ else None
189
+ ),
190
+ "average_holding_days": sum(
191
+ (Decimal(trade.holding_days) for trade in closed_trades), Decimal("0")
192
+ )
193
+ / Decimal(count),
194
+ }
@@ -0,0 +1,61 @@
1
+ """已完成回测的日末净值报告;不重新执行策略或改写权威结果。"""
2
+
3
+ from decimal import Decimal
4
+
5
+ from quant_core.app.backtest.metrics import daily_equity_points, daily_returns
6
+ from quant_core.app.backtest.report_schema import (
7
+ BenchmarkSeries,
8
+ DailyPerformance,
9
+ PerformanceReport,
10
+ ReturnDistribution,
11
+ )
12
+ from quant_core.app.backtest.schema import BacktestResult
13
+
14
+
15
+ class PerformanceReportService:
16
+ def build(
17
+ self, result: BacktestResult, benchmark: BenchmarkSeries | None = None
18
+ ) -> PerformanceReport:
19
+ """按既有指标的交易日日末采样计算;相对收益为净值之比,不混用研究标签。"""
20
+ points = daily_equity_points(result.equity_curve)
21
+ closes = {point.time.date(): point.total_value for point in points}
22
+ rates = daily_returns(result.equity_curve, result.config.initial_cash)
23
+ prices = dict(benchmark.values) if benchmark is not None else {}
24
+ if benchmark is not None and prices.keys() != closes.keys():
25
+ raise ValueError("基准与回测日末日期必须完整一致,禁止前填或截短")
26
+ peak = points[0].total_value if points else Decimal(0)
27
+ daily: list[DailyPerformance] = []
28
+ returns: list[Decimal] = []
29
+ for (day, value), rate in zip(sorted(closes.items()), rates, strict=True):
30
+ if rate is not None:
31
+ returns.append(rate)
32
+ peak = max(peak, value)
33
+ nav = value / result.config.initial_cash
34
+ benchmark_nav = prices[day] / benchmark.initial_value if benchmark is not None else None
35
+ daily.append(
36
+ DailyPerformance(
37
+ day=day,
38
+ nav=nav,
39
+ return_rate=rate,
40
+ drawdown=(peak - value) / peak if peak > 0 else Decimal(0),
41
+ benchmark_nav=benchmark_nav,
42
+ relative_nav=nav / benchmark_nav if benchmark_nav is not None else None,
43
+ )
44
+ )
45
+ relative = daily[-1].relative_nav if daily else None
46
+ return PerformanceReport(
47
+ daily=tuple(daily),
48
+ fees=sum((fill.fees.total for fill in result.fills), Decimal(0)),
49
+ distribution=ReturnDistribution(
50
+ count=len(returns),
51
+ negative=sum(rate < 0 for rate in returns),
52
+ zero=sum(rate == 0 for rate in returns),
53
+ positive=sum(rate > 0 for rate in returns),
54
+ minimum=min(returns) if returns else None,
55
+ maximum=max(returns) if returns else None,
56
+ mean=sum(returns, Decimal(0)) / len(returns) if returns else None,
57
+ ),
58
+ benchmark_name=benchmark.name if benchmark else None,
59
+ benchmark_revision=benchmark.revision if benchmark else None,
60
+ relative_total_return=relative - 1 if relative is not None else None,
61
+ )
@@ -0,0 +1,64 @@
1
+ """回测派生报告与显式基准的不可变数据契约。"""
2
+
3
+ from datetime import date
4
+ from decimal import Decimal
5
+
6
+ from pydantic import BaseModel, ConfigDict, Field, model_validator
7
+
8
+
9
+ class BenchmarkSeries(BaseModel):
10
+ """明确起始基准及版本的日末价格序列,日期必须完整对齐。"""
11
+
12
+ model_config = ConfigDict(frozen=True)
13
+ name: str
14
+ revision: str = Field(min_length=1)
15
+ initial_value: Decimal = Field(gt=0)
16
+ values: tuple[tuple[date, Decimal], ...]
17
+
18
+ @model_validator(mode="after")
19
+ def validate_prices(self) -> "BenchmarkSeries":
20
+ days = [day for day, _ in self.values]
21
+ if days != sorted(set(days)) or any(
22
+ not value.is_finite() or value <= 0 for _, value in self.values
23
+ ):
24
+ raise ValueError("基准日期必须递增无重复,价格必须为有限正值")
25
+ return self
26
+
27
+
28
+ class DailyPerformance(BaseModel):
29
+ """与既有日末采样口径一致的净值单点。"""
30
+
31
+ model_config = ConfigDict(frozen=True)
32
+ day: date
33
+ nav: Decimal
34
+ return_rate: Decimal | None
35
+ drawdown: Decimal
36
+ benchmark_nav: Decimal | None = None
37
+ relative_nav: Decimal | None = None
38
+
39
+
40
+ class ReturnDistribution(BaseModel):
41
+ """实际账户日收益分布,缺失收益不计入样本。"""
42
+
43
+ model_config = ConfigDict(frozen=True)
44
+ count: int
45
+ negative: int
46
+ zero: int
47
+ positive: int
48
+ minimum: Decimal | None
49
+ maximum: Decimal | None
50
+ mean: Decimal | None
51
+
52
+
53
+ class PerformanceReport(BaseModel):
54
+ """只从已完成结果派生的报告,不修改交易事实。"""
55
+
56
+ model_config = ConfigDict(frozen=True)
57
+ daily: tuple[DailyPerformance, ...]
58
+ distribution: ReturnDistribution
59
+ fees: Decimal
60
+ benchmark_name: str | None = None
61
+ benchmark_revision: str | None = None
62
+ relative_total_return: Decimal | None = None
63
+ return_basis: str = "actual_account_after_fees"
64
+ drawdown_basis: str = "daily_close_peak_excluding_initial_cash"