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,150 @@
1
+ """
2
+ Market State Resolver - 市场交易状态增量事实投影
3
+
4
+ 把按时间推进的 MarketTimeSlice 中的 TradingStateEvent / PriceLimitEvent
5
+ 投影为 point-in-time、不可变的 InstrumentMarketState@T(SSOT 见 DECISIONS.md
6
+ 2026-09-04「市场状态采用增量事实投影」)。
7
+
8
+ 状态延续规则(Canonical 语义,市场无关):
9
+ - 事实从 event_time 开始生效,持续到后续事实显式覆盖;
10
+ - 当前片没有状态事件不表示恢复交易——事件缺席延续旧状态;
11
+ - 首次没有任何状态事实时为 UNKNOWN;
12
+ - 只有显式 TRADING 事件才能从 SUSPENDED / HALTED 等状态恢复;
13
+ - 价格限制事实同理增量生效;没有价格限制的市场可以完全不提供
14
+ PriceLimitEvent,投影中 price_limit 恒为 None;
15
+ - BarEvent 等其他市场事实不参与投影:禁止从 Bar 推断停牌或涨跌停封板。
16
+
17
+ 边界:本模块属于 Market 域,只消费 MarketTimeSlice 纯市场事实,
18
+ 不 import Order Execution / Portfolio / Backtest / Trading Runtime;
19
+ 不输出订单的 ALLOW / DEFER / REJECT(该决策属于 Order Execution 的
20
+ TradabilityPolicy)。
21
+ """
22
+
23
+ from datetime import datetime
24
+
25
+ from quant_core.app.data.exceptions import MarketDataValidationError
26
+ from quant_core.app.data.schema.event_schema import MarketTimeSlice
27
+ from quant_core.app.data.schema.trading_state_schema import (
28
+ DailyStateSnapshotEventPayload,
29
+ InstrumentMarketState,
30
+ PriceLimitEventPayload,
31
+ PriceLimitState,
32
+ TradingState,
33
+ TradingStateEventPayload,
34
+ )
35
+
36
+
37
+ class MarketStateResolver:
38
+ """增量市场状态投影器(有状态、按时间片顺序消费)
39
+
40
+ 用法:按市场时间顺序对每个 MarketTimeSlice 调用 apply_slice,
41
+ 之后读取投影。投影不可变,只能被后续事实更新。
42
+ """
43
+
44
+ def __init__(self) -> None:
45
+ # instrument_id -> (生效时间, 交易状态, 来源事件ID);仅由显式状态事实写入。
46
+ # source event ID 随状态值一起生效、延续与覆盖,保证 provenance 与值同步。
47
+ self._states: dict[str, tuple[datetime, TradingState, str | None]] = {}
48
+ # instrument_id -> 最新价格限制投影(含 source_event_id);仅由显式价格限制事实写入
49
+ self._limits: dict[str, PriceLimitState | None] = {}
50
+ # 最近一次成功消费的 slice 时间;投影只允许沿市场时间单调前进
51
+ self._last_slice_time: datetime | None = None
52
+
53
+ def apply_slice(self, time_slice: MarketTimeSlice) -> dict[str, InstrumentMarketState]:
54
+ """消费一个时间片内的事实并更新投影,返回全部已知标的的当前状态
55
+
56
+ 时间推进约束:slice 时间必须严格晚于上一片(相同时间重复 apply
57
+ 同样拒绝),防止较早时间片覆盖较新状态。校验全部通过后才修改
58
+ 内部状态,失败时不产生任何部分修改(原子性)。
59
+ 状态值、as_of 与来源 event_id 三者作为同一事实整体生效/覆盖。
60
+ """
61
+ if self._last_slice_time is not None and time_slice.event_time <= self._last_slice_time:
62
+ raise MarketDataValidationError(
63
+ f"MarketTimeSlice 时间必须严格递增:收到 {time_slice.event_time},"
64
+ f"但已消费到 {self._last_slice_time}(更早或重复的时间片会覆盖较新状态)"
65
+ )
66
+ # 先完整计算本片更新,再统一提交;循环内不改 self,保证失败原子性。
67
+ # 快照先于增量应用:快照建立「日基线」(可显式 UNKNOWN / 清除限价),
68
+ # 同片内的增量事实更具体、后生效覆盖快照(DECISIONS 2026-09-06 Q1-A)。
69
+ state_updates: list[tuple[str, tuple[datetime, TradingState, str | None]]] = []
70
+ limit_updates: list[tuple[str, PriceLimitState]] = []
71
+ snapshot_state_updates: list[tuple[str, tuple[datetime, TradingState, str | None]]] = []
72
+ snapshot_limit_updates: list[tuple[str, PriceLimitState | None]] = []
73
+ for event in time_slice.events:
74
+ payload = event.payload
75
+ if isinstance(payload, TradingStateEventPayload):
76
+ state_updates.append(
77
+ (payload.instrument_id, (event.event_time, payload.state, event.event_id))
78
+ )
79
+ elif isinstance(payload, PriceLimitEventPayload):
80
+ limit_updates.append(
81
+ (
82
+ payload.instrument_id,
83
+ PriceLimitState(
84
+ limit_up=payload.limit_up,
85
+ limit_down=payload.limit_down,
86
+ buy_side_locked=payload.buy_side_locked,
87
+ sell_side_locked=payload.sell_side_locked,
88
+ as_of=event.event_time,
89
+ source_event_id=event.event_id,
90
+ ),
91
+ )
92
+ )
93
+ elif isinstance(payload, DailyStateSnapshotEventPayload):
94
+ snapshot_state_updates.append(
95
+ (
96
+ payload.instrument_id,
97
+ (event.event_time, payload.trading_state, event.event_id),
98
+ )
99
+ )
100
+ snapshot_limit_updates.append(
101
+ (
102
+ payload.instrument_id,
103
+ None
104
+ if payload.limit_up is None or payload.limit_dn is None
105
+ else PriceLimitState(
106
+ limit_up=payload.limit_up,
107
+ limit_down=payload.limit_dn,
108
+ buy_side_locked=False,
109
+ sell_side_locked=False,
110
+ as_of=event.event_time,
111
+ source_event_id=event.event_id,
112
+ ),
113
+ )
114
+ )
115
+ for instrument_id, entry in snapshot_state_updates:
116
+ self._states[instrument_id] = entry
117
+ for instrument_id, limit in snapshot_limit_updates:
118
+ self._limits[instrument_id] = limit
119
+ for instrument_id, entry in state_updates:
120
+ self._states[instrument_id] = entry
121
+ for instrument_id, limit in limit_updates:
122
+ self._limits[instrument_id] = limit
123
+ self._last_slice_time = time_slice.event_time
124
+ return self.snapshot()
125
+
126
+ def snapshot(self) -> dict[str, InstrumentMarketState]:
127
+ """全部已知标的的当前 point-in-time 状态(不可变投影,新对象)"""
128
+ instrument_ids = set(self._states) | set(self._limits)
129
+ return {instrument_id: self.resolve(instrument_id) for instrument_id in instrument_ids}
130
+
131
+ def resolve(self, instrument_id: str) -> InstrumentMarketState:
132
+ """单标的当前 point-in-time 状态;从未有任何事实时交易状态为 UNKNOWN"""
133
+ state_entry = self._states.get(instrument_id)
134
+ limit = self._limits.get(instrument_id)
135
+ if state_entry is None:
136
+ return InstrumentMarketState(
137
+ instrument_id=instrument_id,
138
+ trading_state_as_of=None,
139
+ trading_state=TradingState.UNKNOWN,
140
+ price_limit=limit,
141
+ trading_state_event_id=None,
142
+ )
143
+ trading_state_as_of, state, event_id = state_entry
144
+ return InstrumentMarketState(
145
+ instrument_id=instrument_id,
146
+ trading_state_as_of=trading_state_as_of,
147
+ trading_state=state,
148
+ price_limit=limit,
149
+ trading_state_event_id=event_id,
150
+ )
@@ -0,0 +1,64 @@
1
+ """Runtime 消费的最小市场、策略、账户和同步交易契约。"""
2
+
3
+ from typing import Protocol, runtime_checkable
4
+
5
+ from quant_core.app.data.schema.event_schema import MarketTimeSlice
6
+ from quant_core.app.data.schema.exchange_operating_state import ExchangeOperatingState
7
+ from quant_core.app.data.schema.trading_state_schema import InstrumentMarketState
8
+ from quant_core.app.order_execution.interface.public.execution_account import IExecutionReservation
9
+ from quant_core.app.portfolio.interface.public.portfolio import IPortfolioUpdate
10
+ from quant_core.app.strategy.schema.portfolio_target import PortfolioDecision
11
+ from quant_core.app.strategy.schema.signal_schema import Signal
12
+
13
+
14
+ @runtime_checkable
15
+ class StrategyRuntimeProtocol(Protocol):
16
+ """策略执行能力面(与 StrategyRuntimeService.run_slice 同形)"""
17
+
18
+ decisions: tuple[PortfolioDecision, ...]
19
+
20
+ async def run_slice(self, time_slice: MarketTimeSlice) -> list[Signal]:
21
+ """执行一个时间片并返回该片 Signal 批次"""
22
+ ...
23
+
24
+
25
+ @runtime_checkable
26
+ class MarketStateProjectionProtocol(Protocol):
27
+ """市场状态增量投影能力面(MarketStateResolver 的最小等价 Port)"""
28
+
29
+ def apply_slice(self, time_slice: MarketTimeSlice) -> dict[str, InstrumentMarketState]:
30
+ """消费一个时间片事实,返回全部已知标的的当前 point-in-time 状态"""
31
+ ...
32
+
33
+
34
+ @runtime_checkable
35
+ class ExchangeStateProjectionProtocol(Protocol):
36
+ """交易所运行状态增量投影能力面(T4R;ExchangeStateResolver 的最小等价 Port)
37
+
38
+ 交易所运行状态唯一 SSOT:Runtime 每片消费一次,投影同时供
39
+ Order Execution(报单/撮合准入、DAY 到期)与 StepResult(UI/Agent
40
+ 可见性)消费;下游不得私有解释 Session 事件。
41
+ """
42
+
43
+ def apply_slice(self, time_slice: MarketTimeSlice) -> dict[str, ExchangeOperatingState]:
44
+ """消费一个时间片事实,返回全部已知交易所的当前 point-in-time 状态"""
45
+ ...
46
+
47
+
48
+ @runtime_checkable
49
+ class RuntimePortfolioProtocol(
50
+ IPortfolioUpdate,
51
+ IExecutionReservation,
52
+ Protocol,
53
+ ):
54
+ """Runtime 所需的组合 Portfolio 能力;只组合既有 Port,不复制方法
55
+
56
+ Runtime 要求同一个 Portfolio 对象同时提供:
57
+ - IPortfolioUpdate(apply_fill / mark_to_market /
58
+ settle_trading_day / snapshot)
59
+ - IExecutionAccountView(available_cash / available_quantity,
60
+ 撮合期只读账户视图,直接传给 process_market_slice)
61
+
62
+ 实现(如 T3 内存模拟组合)零修改即结构化满足;
63
+ Runtime 不 import 任何具体 Portfolio 类。
64
+ """
@@ -0,0 +1,129 @@
1
+ """
2
+ Trading Runtime Schema - Clock / TraceEntry / RuntimeStepResult
3
+
4
+ Runtime 是不知道调用场景(Backtest/Paper/Live)的共享事件循环内核;
5
+ 单时间片因果顺序见 DECISIONS.md 2026-09-04「Backtest 单时间片采用
6
+ 旧订单成交在前、新策略决策在后」与 `app/trading_runtime/SPEC.md` §5。
7
+
8
+ 边界:RuntimeStepResult 是一次 step 的结构化输出;集合全部不可变元组
9
+ 并保持确定顺序。本域不实现撮合/组合业务,只编排。
10
+ """
11
+
12
+ from dataclasses import dataclass
13
+ from datetime import datetime
14
+ from typing import Protocol, runtime_checkable
15
+
16
+ from pydantic import BaseModel, ConfigDict, Field, field_validator
17
+
18
+ from quant_core.app.data.schema.exchange_operating_state import ExchangeOperatingState
19
+ from quant_core.app.order_execution.domain.order_event import (
20
+ ExecutionAttempt,
21
+ Fill,
22
+ OrderTransition,
23
+ )
24
+ from quant_core.app.order_execution.domain.order_value import OrderAck, OrderIntent
25
+ from quant_core.app.order_execution.schema.order_request_schema import OrderRequest
26
+ from quant_core.app.portfolio.portfolio_schema import PortfolioSnapshot
27
+ from quant_core.app.strategy.schema.portfolio_target import PortfolioDecision
28
+ from quant_core.app.strategy.schema.signal_schema import Signal
29
+
30
+
31
+ @runtime_checkable
32
+ class ClockProtocol(Protocol):
33
+ """场景无关时钟:当前市场时间由调用方推进(禁止读 wall clock)"""
34
+
35
+ def now(self) -> datetime:
36
+ """返回当前市场时间(timezone-aware)"""
37
+ ...
38
+
39
+
40
+ class TraceEntry(BaseModel):
41
+ """最小通用 trace 记录(不是 Backtest DecisionTrace;后者归 T7)"""
42
+
43
+ model_config = ConfigDict(frozen=True)
44
+
45
+ event_time: datetime = Field(..., description="发生市场时间(timezone-aware)")
46
+ kind: str = Field(..., description="条目类别(如 order_ack / fill / defer)")
47
+ detail: str = Field(..., description="人类可读摘要(审计用,非行为依据)")
48
+
49
+ @field_validator("event_time")
50
+ @classmethod
51
+ def _check_tz(cls, value: datetime) -> datetime:
52
+ if value.tzinfo is None:
53
+ raise ValueError("TraceEntry.event_time 必须 timezone-aware")
54
+ return value
55
+
56
+
57
+ def _require_tz_aware(value: datetime) -> datetime:
58
+ if value.tzinfo is None:
59
+ raise ValueError("RuntimeStepResult.slice_time 必须 timezone-aware")
60
+ return value
61
+
62
+
63
+ @dataclass(frozen=True, slots=True)
64
+ class RuntimeStepResult:
65
+ """单时间片处理结果(片内因果顺序的输出形态)
66
+
67
+ 集合为不可变元组并保持处理顺序;portfolio_snapshot 是本片估值后的
68
+ 组合投影。类型参数化字段按业务对象组织,禁止通用 dict 透传。
69
+ """
70
+
71
+ slice_time: datetime
72
+ portfolio_snapshot: PortfolioSnapshot
73
+ fills: tuple[Fill, ...] = ()
74
+ execution_attempts: tuple[ExecutionAttempt, ...] = ()
75
+ order_acks: tuple[OrderAck, ...] = ()
76
+ order_updates: tuple[OrderTransition, ...] = ()
77
+ signals: tuple[Signal, ...] = ()
78
+ portfolio_decisions: tuple[PortfolioDecision, ...] = ()
79
+ strategy_order_requests: tuple[OrderRequest, ...] = ()
80
+ order_intents: tuple[OrderIntent, ...] = ()
81
+ exchange_states: tuple[ExchangeOperatingState, ...] = ()
82
+ trace_entries: tuple[TraceEntry, ...] = ()
83
+
84
+ def __post_init__(self) -> None:
85
+ _require_tz_aware(self.slice_time)
86
+ self._check_point_in_time_consistency()
87
+
88
+ def _check_point_in_time_consistency(self) -> None:
89
+ """RuntimeStepResult@T 中所有「本片产生」的对象时间必须精确等于 T"""
90
+ t = self.slice_time
91
+ for fill in self.fills:
92
+ if fill.fill_time != t:
93
+ raise ValueError(f"Fill.fill_time {fill.fill_time} 必须等于 slice_time {t}")
94
+ for attempt in self.execution_attempts:
95
+ if attempt.event_time != t:
96
+ raise ValueError(
97
+ f"ExecutionAttempt.event_time {attempt.event_time} 必须等于 slice_time {t}"
98
+ )
99
+ for ack in self.order_acks:
100
+ if ack.event_time != t:
101
+ raise ValueError(f"OrderAck.event_time {ack.event_time} 必须等于 slice_time {t}")
102
+ for update in self.order_updates:
103
+ if update.event_time != t:
104
+ raise ValueError(
105
+ f"OrderUpdate.event_time {update.event_time} 必须等于 slice_time {t}"
106
+ )
107
+ for signal in self.signals:
108
+ if signal.event_time != t:
109
+ raise ValueError(f"Signal.event_time {signal.event_time} 必须等于 slice_time {t}")
110
+ for request in self.strategy_order_requests:
111
+ if request.event_time != t:
112
+ raise ValueError(
113
+ f"OrderRequest.event_time {request.event_time} 必须等于 slice_time {t}"
114
+ )
115
+ for intent in self.order_intents:
116
+ if intent.creation_event_time != t:
117
+ raise ValueError(
118
+ f"OrderIntent.creation_event_time {intent.creation_event_time} "
119
+ f"必须等于 slice_time {t}"
120
+ )
121
+ for entry in self.trace_entries:
122
+ if entry.event_time != t:
123
+ raise ValueError(
124
+ f"TraceEntry.event_time {entry.event_time} 必须等于 slice_time {t}"
125
+ )
126
+ if self.portfolio_snapshot.as_of != t:
127
+ raise ValueError(
128
+ f"PortfolioSnapshot.as_of {self.portfolio_snapshot.as_of} 必须等于 slice_time {t}"
129
+ )