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,40 @@
1
+ """Slippage Model - 可注入滑点模型(T5)
2
+
3
+ SSOT:T5 Task「Mock Fee / Slippage 参数(2026-09-04 用户确认)」。
4
+
5
+ - SlippageModelProtocol 是 order_execution 消费方拥有的最小消费面。
6
+ - FixedBpsSlippageModel:固定 bps 滑点——BUY = Open × (1 + bps/10000);
7
+ SELL = Open × (1 - bps/10000)。只消费 Open,不读取 High/Low/Close。
8
+ - 全部 Decimal、不 quantize、无状态、相同输入结果一致。
9
+ """
10
+
11
+ from decimal import Decimal
12
+ from typing import cast
13
+
14
+ from quant_core.app.order_execution.constants import OrderSide
15
+ from quant_core.app.order_execution.validators import reject_float_amount
16
+
17
+
18
+ class FixedBpsSlippageModel:
19
+ """固定 bps 滑点模型(Mock 确定性配置)"""
20
+
21
+ def __init__(self, fixed_slippage_bps: Decimal) -> None:
22
+ checked = reject_float_amount(fixed_slippage_bps, "fixed_slippage_bps")
23
+ bps = checked if isinstance(checked, Decimal) else Decimal(cast(int | str, checked))
24
+ if not bps.is_finite():
25
+ raise ValueError(
26
+ "fixed_slippage_bps 必须是有限 Decimal,禁止字符串形式的 NaN / Infinity / sNaN"
27
+ )
28
+ if bps < 0:
29
+ raise ValueError(f"fixed_slippage_bps 必须 >= 0,实际 {bps}")
30
+ self.ratio = bps / Decimal("10000")
31
+
32
+ def apply(self, side: OrderSide, bar_open: Decimal) -> Decimal:
33
+ reject_float_amount(bar_open, "bar_open")
34
+ if side is OrderSide.BUY:
35
+ price = bar_open * (Decimal("1") + self.ratio)
36
+ else:
37
+ price = bar_open * (Decimal("1") - self.ratio)
38
+ if price <= 0:
39
+ raise ValueError(f"滑点后成交价必须 > 0,实际 {price}")
40
+ return price
@@ -0,0 +1,174 @@
1
+ """Tradability Policy - 纯决策、可注入的市场可交易性判断(T4)
2
+
3
+ 语义 SSOT 见 `app/order_execution/SPEC.md`、DECISIONS.md 2026-09-04
4
+ 「回测撮合以通用市场交易事实和可替换 Policy 表达市场限制」、T4 Task 及用户裁定:
5
+
6
+ Market Facts + Order
7
+ |
8
+ v
9
+ TradabilityPolicy
10
+ |
11
+ +── ALLOW
12
+ |
13
+ +── DEFER(reason)
14
+
15
+ 边界:
16
+ - Policy 是纯函数式决策:只消费 OrderSnapshot 最小读取面与 InstrumentMarketState,
17
+ 返回结构化 TradabilityDecisionRecord;不修改 Order / Portfolio,不产生
18
+ Fill / OrderUpdate / OrderAck;DEFER 只表达「本次市场暂不可成交」,
19
+ Order 保持 PENDING,状态恢复后可继续参与后续撮合。
20
+ - 静态非法输入(非法 id / quantity / order type / execution policy)属于
21
+ submit 阶段 REJECT,与本 Policy 无关;Policy 不返回 REJECT。
22
+ - 不读取 wall clock / Runtime mode,不知道 Backtest/Paper/Live;
23
+ 相同输入返回逐字段相同结果。
24
+ - TradingState 的禁止交易优先级高于 PriceLimitState;原因码与实际阻塞
25
+ 条件一一对应(显式决策表,无嵌套分支、无字符串 reason)。
26
+ - 价格限制语义以 PriceLimitEvent 事实为准;Policy 不从 Bar OHLC 推断
27
+ 封板,不计算涨跌停价格,不读 ST / 板块 / 交易所涨跌幅规则。
28
+ """
29
+
30
+ from quant_core.app.data.schema.trading_state_schema import (
31
+ InstrumentMarketState,
32
+ PriceLimitState,
33
+ TradingState,
34
+ )
35
+ from quant_core.app.order_execution.constants import (
36
+ ExecutionDeferReason,
37
+ OrderSide,
38
+ TradabilityDecision,
39
+ )
40
+ from quant_core.app.order_execution.domain.order_value import (
41
+ OrderSnapshot,
42
+ )
43
+ from quant_core.app.order_execution.domain.order_value import (
44
+ TradabilityDecision as TradabilityDecisionRecord,
45
+ )
46
+
47
+ # TradingState 显式决策表(禁止交易状态 → 一一对应的原因码)。
48
+ # TradingState 的禁止优先级高于 PriceLimitState:表内命中即 DEFER,
49
+ # 不再检查价格限制。TRADING 不在表内,进入价格限制检查。
50
+ _BLOCKED_TRADING_STATE: dict[TradingState, ExecutionDeferReason] = {
51
+ TradingState.SUSPENDED: ExecutionDeferReason.SUSPENDED,
52
+ TradingState.HALTED: ExecutionDeferReason.HALTED,
53
+ # AUCTION / CLOSED:非连续交易时段,保守 DEFER(T1 枚举复用,不新增同义状态)
54
+ TradingState.AUCTION: ExecutionDeferReason.SESSION_NOT_TRADABLE,
55
+ TradingState.CLOSED: ExecutionDeferReason.SESSION_NOT_TRADABLE,
56
+ TradingState.UNKNOWN: ExecutionDeferReason.TRADING_STATE_UNKNOWN,
57
+ }
58
+
59
+
60
+ def _state_evidence(market_state: InstrumentMarketState) -> tuple[str, ...]:
61
+ """本次通用 TradingState 检查实际消费的事实引用
62
+
63
+ provenance 来自投影携带的最近生效 TradingStateEvent ID;
64
+ UNKNOWN 默认态 / 非事件来源为 None——不伪造引用。
65
+ """
66
+ if market_state.trading_state_event_id is None:
67
+ return ()
68
+ return (market_state.trading_state_event_id,)
69
+
70
+
71
+ def _price_limit_evidence(price_limit: PriceLimitState) -> tuple[str, ...]:
72
+ """本次 PriceLimit 检查实际消费的事实引用(None 来源不伪造)"""
73
+ if price_limit.source_event_id is None:
74
+ return ()
75
+ return (price_limit.source_event_id,)
76
+
77
+
78
+ def _merge_evidence(*parts: tuple[str, ...]) -> tuple[str, ...]:
79
+ """合并各检查阶段的事实引用,去重且保序
80
+
81
+ 同一物理事件可为多个检查消费同一引用:真实日级事实以单条
82
+ DAILY_STATE_SNAPSHOT 同时承载交易状态与涨跌停(T5 真实数据回放发现),
83
+ 两类 evidence 的 source_event_id 相同——事件引用一次即可,模型边界
84
+ 禁止重复引用(TradabilityDecisionRecord validator)。
85
+ """
86
+ return tuple(dict.fromkeys(ref for part in parts for ref in part))
87
+
88
+
89
+ def _blocked_trading_state_reason(
90
+ order: OrderSnapshot, market_state: InstrumentMarketState
91
+ ) -> ExecutionDeferReason | None:
92
+ """两个 Policy 共用的通用交易状态检查(TradingState 优先级高于 PriceLimitState)
93
+
94
+ 标的不一致属于矛盾输入,立即抛错;命中禁止状态返回一一对应的原因码,
95
+ 否则返回 None(TRADING,进入各自的市场特定判断)。
96
+ """
97
+ if order.intent.instrument_id != market_state.instrument_id:
98
+ raise ValueError(
99
+ f"订单标的 {order.intent.instrument_id} 与市场投影标的 "
100
+ f"{market_state.instrument_id} 不一致"
101
+ )
102
+ return _BLOCKED_TRADING_STATE.get(market_state.trading_state)
103
+
104
+
105
+ class NoPriceLimitTradabilityPolicy:
106
+ """无价格限制市场的通用 Policy(用户裁定 2026-09-04:「无价格限制 ≠ 无视交易状态」)
107
+
108
+ 精确语义:
109
+ - 非 TRADING 状态(SUSPENDED/HALTED/AUCTION/CLOSED/UNKNOWN)按通用矩阵 DEFER;
110
+ - TRADING 时**始终 ALLOW**——即使投影意外携带涨跌停锁定也 ALLOW,
111
+ 证明价格限制由可替换 Policy 拥有,而非引擎内置。
112
+ 无状态、纯决策,不读取 wall clock / Runtime mode / 市场字符串 / Provider。
113
+ """
114
+
115
+ def decide(
116
+ self, order: OrderSnapshot, market_state: InstrumentMarketState
117
+ ) -> TradabilityDecisionRecord:
118
+ blocked = _blocked_trading_state_reason(order, market_state)
119
+ evidence = _state_evidence(market_state)
120
+ if blocked is not None:
121
+ return TradabilityDecisionRecord(
122
+ decision=TradabilityDecision.DEFER,
123
+ defer_reason=blocked,
124
+ evidence_event_refs=evidence,
125
+ )
126
+ # 明确忽略 PriceLimit:其 evidence 即使存在也不进入引用
127
+ return TradabilityDecisionRecord(
128
+ decision=TradabilityDecision.ALLOW, defer_reason=None, evidence_event_refs=evidence
129
+ )
130
+
131
+
132
+ class ChinaEquityTradabilityPolicy:
133
+ """A 股市场规则 Policy:停牌/集合竞价等禁止 + 涨跌停方向锁单
134
+
135
+ 决策矩阵(用户裁定 2026-09-04):
136
+ - SUSPENDED / HALTED / CLOSED / UNKNOWN / AUCTION × BUY/SELL → DEFER;
137
+ - TRADING + 涨停封板(buy_side_locked)→ BUY DEFER / SELL ALLOW;
138
+ - TRADING + 跌停封板(sell_side_locked)→ BUY ALLOW / SELL DEFER;
139
+ - TRADING + 未锁定 / 无 PriceLimitEvent → ALLOW。
140
+ 无状态:不缓存历史 MarketState(历史投影由 T1 MarketStateResolver 负责)。
141
+ """
142
+
143
+ def decide(
144
+ self, order: OrderSnapshot, market_state: InstrumentMarketState
145
+ ) -> TradabilityDecisionRecord:
146
+ blocked = _blocked_trading_state_reason(order, market_state)
147
+ if blocked is not None:
148
+ # 状态已先行阻塞:只引用实际消费的状态事实,不追加未消费的 PriceLimit
149
+ return TradabilityDecisionRecord(
150
+ decision=TradabilityDecision.DEFER,
151
+ defer_reason=blocked,
152
+ evidence_event_refs=_state_evidence(market_state),
153
+ )
154
+
155
+ price_limit = market_state.price_limit
156
+ evidence = _state_evidence(market_state)
157
+ if price_limit is not None:
158
+ # TRADING 且携带 PriceLimit:Policy 实际检查了状态与价格限制两类事实
159
+ evidence = _merge_evidence(evidence, _price_limit_evidence(price_limit))
160
+ if order.intent.side is OrderSide.BUY and price_limit.buy_side_locked:
161
+ return TradabilityDecisionRecord(
162
+ decision=TradabilityDecision.DEFER,
163
+ defer_reason=ExecutionDeferReason.PRICE_LIMIT_BUY_BLOCKED,
164
+ evidence_event_refs=evidence,
165
+ )
166
+ if order.intent.side is OrderSide.SELL and price_limit.sell_side_locked:
167
+ return TradabilityDecisionRecord(
168
+ decision=TradabilityDecision.DEFER,
169
+ defer_reason=ExecutionDeferReason.PRICE_LIMIT_SELL_BLOCKED,
170
+ evidence_event_refs=evidence,
171
+ )
172
+ return TradabilityDecisionRecord(
173
+ decision=TradabilityDecision.ALLOW, defer_reason=None, evidence_event_refs=evidence
174
+ )
@@ -0,0 +1,40 @@
1
+ """Order Execution 领域内共享校验器(不放 common:仅本域复用)"""
2
+
3
+ from decimal import Decimal
4
+
5
+
6
+ def validate_identifier(value: object, field: str) -> str:
7
+ """业务标识(intent_id / order_id / ack_id / fill_id / attempt_id / strategy_id)
8
+
9
+ 至少拒绝:非字符串、空串、纯空白、含任何空白字符。
10
+ """
11
+ if not isinstance(value, str):
12
+ raise ValueError(f"{field} 必须是非空字符串标识")
13
+ if not value or value.strip() != value or any(ch.isspace() for ch in value):
14
+ raise ValueError(f"{field} 不允许为空或包含空白字符:{value!r}")
15
+ return value
16
+
17
+
18
+ def reject_float_amount(value: object, field: str) -> object:
19
+ """金额/价格字段严格拒绝 float 与非有限 Decimal(禁止浮点/Inf 进入资金计算)
20
+
21
+ 接受 Decimal(以及 Pydantic 默认可无损转换的 int 字面量)。
22
+ 统一规则:value.is_finite() 必须为 True(拒绝 NaN / ±Infinity / sNaN)。
23
+ """
24
+ if isinstance(value, float):
25
+ raise ValueError(f"{field} 必须使用 Decimal,禁止 float(避免二进制浮点误差)")
26
+ if isinstance(value, Decimal) and not value.is_finite():
27
+ raise ValueError(f"{field} 必须是有限 Decimal,禁止 NaN / Infinity / sNaN")
28
+ return value
29
+
30
+
31
+ def ensure_finite_amounts(model: object, fields: tuple[str, ...]) -> None:
32
+ """Decimal 解析完成后的二次统一 finite 校验(mode="after")
33
+
34
+ 字符串 "NaN" / "Infinity" 等在 before 阶段还不是 Decimal,会在
35
+ Pydantic 解析后变成非有限 Decimal;此处在解析后统一收口拒绝。
36
+ """
37
+ for name in fields:
38
+ value = getattr(model, name)
39
+ if isinstance(value, Decimal) and not value.is_finite():
40
+ raise ValueError(f"{name} 必须是有限 Decimal,禁止字符串形式的 NaN / Infinity / sNaN")
@@ -0,0 +1,69 @@
1
+ # Portfolio SPEC
2
+
3
+ ## 1. Domain Purpose
4
+
5
+ `portfolio` 负责维护特定运行账户的资金、持仓、成本、估值、损益和风险状态,并向 Strategy 和 Trading Runtime 提供只读 PortfolioSnapshot。
6
+
7
+ ## 2. Responsibilities
8
+
9
+ - 应用 Order Execution 产生的 Fill。
10
+ - 更新 Cash、Position、CostBasis 和 RealizedPnL。
11
+ - 使用当前可用市场价格计算估值、UnrealizedPnL 与 Exposure。
12
+ - 提供 point-in-time `PortfolioSnapshot`。
13
+ - 隔离 Backtest、Paper 和 Live 的账户状态。
14
+ - 为 Order Planning 提供仓位计算、交易约束与下单前风险检查所需状态。
15
+
16
+ ## 3. Non-Responsibilities
17
+
18
+ - 不产生 Strategy Signal。
19
+ - 不创建、撮合或路由 Order。
20
+ - 不推进 Runtime Clock。
21
+ - 不维护 Opportunity 或 Watchlist。
22
+ - 不直接读取 Provider 或 Broker-specific 类型。
23
+
24
+ ## 4. Main Concepts
25
+
26
+ ```text
27
+ Fill + Market Valuation Facts
28
+ ↓
29
+ Portfolio
30
+ ├── Cash
31
+ ├── Position
32
+ ├── CostBasis
33
+ ├── RealizedPnL
34
+ ├── UnrealizedPnL
35
+ └── Exposure
36
+ ↓
37
+ PortfolioSnapshot
38
+ ```
39
+
40
+ `PortfolioSnapshot` 是某一市场时刻的只读组合视图。Strategy 可以读取它,但不能修改 Portfolio。
41
+
42
+ ## 5. Fill Rule
43
+
44
+ Fill 是确认成交的事实,也是 Portfolio 因交易而改变资金和持仓的唯一输入。OrderIntent、Order Accepted 或 Signal 均不能直接修改 Portfolio。
45
+
46
+ ## 6. Runtime Isolation
47
+
48
+ ```text
49
+ Backtest Account State ─┐
50
+ Paper Account State ─┼── 相同 Portfolio 语义,不共享可变状态
51
+ Live Account State ─┘
52
+ ```
53
+
54
+ 不同运行环境可以使用不同存储或同步机制,但 Cash、Position、PnL、Exposure 与 Snapshot 的 Canonical 语义保持一致。
55
+
56
+ ## 7. Cross-Domain Dependencies
57
+
58
+ - 消费 Order Execution 的 Fill。
59
+ - 消费 Market 的估值事实。
60
+ - 向 Strategy 和 Trading Runtime 提供只读 Snapshot 契约。
61
+ - Backtest 负责创建和隔离其运行账户,本域不依赖 Backtest。
62
+
63
+ ## 8. Aggregate Boundary
64
+
65
+ `Portfolio` 是资金、持仓、冻结、结算和公司行动状态的唯一聚合根。`Position`、`PositionLot`、`OrderReservation` 与 `DividendEntitlement` 是聚合内部实体,只能经 Portfolio 应用 Fill、结算或公司行动时改变。
66
+
67
+ 内部实体保护自身局部不变量,例如批次不可超卖、冻结资源不可透支、分红权益不可超额消耗;Portfolio 负责跨实体的原子校验和编排。Snapshot、账本 Schema 与 ORM Model 位于领域边界之外,不得持有另一套可变业务规则。
68
+
69
+ `app/portfolio/domain/` 保持零入口框架、零 ORM、零外部数据 SDK 依赖。当前不存在从 ORM 恢复完整聚合的需求,因此不预建 Mapper。
File without changes
@@ -0,0 +1,32 @@
1
+ """Portfolio 纯领域模型。"""
2
+
3
+ from quant_core.app.portfolio.domain.entitlement_entity import DividendEntitlement
4
+ from quant_core.app.portfolio.domain.portfolio_entity import Portfolio
5
+ from quant_core.app.portfolio.domain.portfolio_event import (
6
+ ClosedLot,
7
+ CorporateActionApplied,
8
+ FillApplied,
9
+ ReservationAction,
10
+ ReservationChanged,
11
+ )
12
+ from quant_core.app.portfolio.domain.portfolio_value import (
13
+ CorporateActionInstruction,
14
+ CorporateActionPhase,
15
+ )
16
+ from quant_core.app.portfolio.domain.position_entity import Position, PositionLot
17
+ from quant_core.app.portfolio.domain.reservation_entity import OrderReservation
18
+
19
+ __all__ = [
20
+ "DividendEntitlement",
21
+ "ClosedLot",
22
+ "CorporateActionApplied",
23
+ "CorporateActionInstruction",
24
+ "CorporateActionPhase",
25
+ "FillApplied",
26
+ "OrderReservation",
27
+ "Portfolio",
28
+ "Position",
29
+ "PositionLot",
30
+ "ReservationAction",
31
+ "ReservationChanged",
32
+ ]
@@ -0,0 +1,45 @@
1
+ """公司行动权益的内部实体。"""
2
+
3
+ from decimal import Decimal
4
+
5
+
6
+ class DividendEntitlement:
7
+ """关联 action/lot 的分红权益及尚未处置数量。"""
8
+
9
+ __slots__ = ("_remaining_quantity", "action_id", "cash_per_share", "lot_id")
10
+
11
+ def __init__(
12
+ self,
13
+ action_id: str,
14
+ lot_id: str,
15
+ quantity: int,
16
+ cash_per_share: Decimal,
17
+ ) -> None:
18
+ if not action_id or not lot_id:
19
+ raise ValueError("分红权益必须关联 action_id 和 lot_id")
20
+ if quantity <= 0:
21
+ raise ValueError("分红权益数量必须 > 0")
22
+ if not cash_per_share.is_finite() or cash_per_share < 0:
23
+ raise ValueError("每股现金分红必须是有限非负 Decimal")
24
+ self.action_id = action_id
25
+ self.lot_id = lot_id
26
+ self._remaining_quantity = quantity
27
+ self.cash_per_share = cash_per_share
28
+
29
+ @property
30
+ def remaining_quantity(self) -> int:
31
+ return self._remaining_quantity
32
+
33
+ def consume(self, quantity: int) -> None:
34
+ """卖出关联批次时消耗权益,禁止超额或反向修改。"""
35
+ if quantity <= 0:
36
+ raise ValueError("分红权益消耗数量必须 > 0")
37
+ if quantity > self.remaining_quantity:
38
+ raise ValueError("分红权益消耗数量超过剩余数量")
39
+ self._remaining_quantity -= quantity
40
+
41
+ def gross_cash_for(self, quantity: int) -> Decimal:
42
+ """返回指定剩余权益数量对应的税前现金基数。"""
43
+ if quantity <= 0 or quantity > self.remaining_quantity:
44
+ raise ValueError("分红权益计税数量必须在剩余数量范围内")
45
+ return Decimal(quantity) * self.cash_per_share