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,165 @@
1
+ """持仓与持仓批次内部实体。"""
2
+
3
+ from datetime import date, datetime
4
+ from decimal import Decimal
5
+
6
+
7
+ class Position:
8
+ """单标的可变持仓,只能由 Portfolio 聚合修改。"""
9
+
10
+ __slots__ = (
11
+ "available_quantity",
12
+ "average_cost",
13
+ "last_price",
14
+ "pending_settlement_quantity",
15
+ "quantity",
16
+ "realized_pnl",
17
+ )
18
+
19
+ def __init__(self, quantity: int, price: Decimal, fee_total: Decimal) -> None:
20
+ self.quantity = quantity
21
+ self.available_quantity = 0
22
+ self.pending_settlement_quantity = quantity
23
+ self.average_cost = (Decimal(quantity) * price + fee_total) / Decimal(quantity)
24
+ self.last_price = price
25
+ self.realized_pnl = Decimal("0")
26
+
27
+ def unrealized_pnl(self) -> Decimal:
28
+ return Decimal(self.quantity) * (self.last_price - self.average_cost)
29
+
30
+ def apply_buy(self, quantity: int, price: Decimal, total_cost: Decimal) -> None:
31
+ """增加当日待结算持仓并按总成本重算均价。"""
32
+ existing_cost = Decimal(self.quantity) * self.average_cost
33
+ self.quantity += quantity
34
+ self.pending_settlement_quantity += quantity
35
+ self.average_cost = (existing_cost + total_cost) / Decimal(self.quantity)
36
+ self.last_price = price
37
+
38
+ def apply_sell(self, quantity: int, price: Decimal, realized_pnl: Decimal) -> None:
39
+ """应用已通过 Portfolio 资金和批次校验的卖出结果。"""
40
+ if quantity > self.available_quantity:
41
+ raise ValueError(
42
+ f"卖出被拒绝:数量 {quantity} 超过可卖 {self.available_quantity}(T+1)"
43
+ )
44
+ self.quantity -= quantity
45
+ self.available_quantity -= quantity
46
+ self.realized_pnl += realized_pnl
47
+ self.last_price = price
48
+
49
+ def apply_bonus(self, quantity: int) -> None:
50
+ """除权日计入红股总持仓,但保持待上市不可卖。"""
51
+ old_cost = Decimal(self.quantity) * self.average_cost
52
+ self.quantity += quantity
53
+ self.pending_settlement_quantity += quantity
54
+ self.average_cost = old_cost / Decimal(self.quantity)
55
+
56
+ def release_bonus(self, quantity: int) -> None:
57
+ """红股上市日将指定数量从待结算转为可卖。"""
58
+ if quantity > self.pending_settlement_quantity:
59
+ raise ValueError("红股数量超过持仓待结算数量")
60
+ self.pending_settlement_quantity -= quantity
61
+ self.available_quantity += quantity
62
+
63
+ def settle(self, locked_quantity: int) -> None:
64
+ """释放普通 T+1 待结算数量,保留未上市红股锁定。"""
65
+ releasable = self.pending_settlement_quantity - locked_quantity
66
+ if releasable < 0:
67
+ raise ValueError("红股锁定数量超过待结算数量")
68
+ self.available_quantity += releasable
69
+ self.pending_settlement_quantity = locked_quantity
70
+
71
+ def mark(self, price: Decimal) -> None:
72
+ self.last_price = price
73
+
74
+
75
+ class PositionLot:
76
+ """拥有独立 lot_id、成本、持有期和可卖时间的持仓批次。"""
77
+
78
+ __slots__ = (
79
+ "_available_on",
80
+ "_available_quantity",
81
+ "_remaining_quantity",
82
+ "_unit_cost",
83
+ "acquired_at",
84
+ "instrument_id",
85
+ "lot_id",
86
+ "original_quantity",
87
+ "source_id",
88
+ )
89
+
90
+ def __init__(
91
+ self,
92
+ *,
93
+ lot_id: str,
94
+ instrument_id: str,
95
+ source_id: str,
96
+ acquired_at: datetime,
97
+ quantity: int,
98
+ unit_cost: Decimal,
99
+ available_quantity: int = 0,
100
+ available_on: date | None = None,
101
+ ) -> None:
102
+ if not lot_id or not instrument_id or not source_id:
103
+ raise ValueError("持仓批次必须包含 lot_id、instrument_id 和 source_id")
104
+ if acquired_at.tzinfo is None:
105
+ raise ValueError("持仓批次 acquired_at 必须 timezone-aware")
106
+ if quantity <= 0:
107
+ raise ValueError("持仓批次数量必须 > 0")
108
+ if available_quantity < 0 or available_quantity > quantity:
109
+ raise ValueError("持仓批次可卖数量必须在总数量范围内")
110
+ if not unit_cost.is_finite() or unit_cost < 0:
111
+ raise ValueError("持仓批次单位成本必须是有限非负 Decimal")
112
+ self.lot_id = lot_id
113
+ self.instrument_id = instrument_id
114
+ self.source_id = source_id
115
+ self.acquired_at = acquired_at
116
+ self._available_on = available_on
117
+ self.original_quantity = quantity
118
+ self._remaining_quantity = quantity
119
+ self._available_quantity = available_quantity
120
+ self._unit_cost = unit_cost
121
+
122
+ @property
123
+ def remaining_quantity(self) -> int:
124
+ return self._remaining_quantity
125
+
126
+ @property
127
+ def available_quantity(self) -> int:
128
+ return self._available_quantity
129
+
130
+ @property
131
+ def available_on(self) -> date | None:
132
+ return self._available_on
133
+
134
+ @property
135
+ def unit_cost(self) -> Decimal:
136
+ return self._unit_cost
137
+
138
+ def close(self, quantity: int) -> None:
139
+ """关闭可卖批次数量,禁止超卖或产生负状态。"""
140
+ if quantity <= 0 or quantity > self.available_quantity:
141
+ raise ValueError("关闭数量超过持仓批次可卖数量")
142
+ self._remaining_quantity -= quantity
143
+ self._available_quantity -= quantity
144
+
145
+ def release(self, available_on: date) -> None:
146
+ """将批次全部剩余数量置为可卖。"""
147
+ if self.remaining_quantity <= 0:
148
+ raise ValueError("已耗尽持仓批次不能释放")
149
+ if self.available_quantity == self.remaining_quantity:
150
+ return
151
+ if self.available_on is not None and available_on < self.available_on:
152
+ raise ValueError("持仓批次可卖日期不允许回退")
153
+ self._available_quantity = self.remaining_quantity
154
+ self._available_on = available_on
155
+
156
+ def apply_bonus_cost(self, bonus_quantity: int) -> Decimal:
157
+ """按送转后总数量摊薄原批次成本,返回红股批次单位成本。"""
158
+ if bonus_quantity <= 0:
159
+ raise ValueError("红股批次数量必须 > 0")
160
+ adjusted_quantity = self.remaining_quantity + bonus_quantity
161
+ adjusted_cost = (
162
+ self.unit_cost * Decimal(self.remaining_quantity) / Decimal(adjusted_quantity)
163
+ )
164
+ self._unit_cost = adjusted_cost
165
+ return adjusted_cost
@@ -0,0 +1,69 @@
1
+ """订单资源冻结的内部实体。"""
2
+
3
+ from decimal import Decimal
4
+
5
+ from quant_core.app.order_execution.constants import OrderSide
6
+
7
+
8
+ class OrderReservation:
9
+ """以 order_id 为身份,跟踪尚未消耗的冻结现金或证券。"""
10
+
11
+ __slots__ = (
12
+ "_remaining_cash",
13
+ "_remaining_quantity",
14
+ "instrument_id",
15
+ "order_id",
16
+ "side",
17
+ )
18
+
19
+ def __init__(
20
+ self,
21
+ *,
22
+ order_id: str,
23
+ instrument_id: str,
24
+ side: OrderSide,
25
+ remaining_quantity: int,
26
+ remaining_cash: Decimal,
27
+ ) -> None:
28
+ if not order_id or not instrument_id:
29
+ raise ValueError("订单冻结必须关联 order_id 和 instrument_id")
30
+ if remaining_quantity <= 0:
31
+ raise ValueError("订单冻结数量必须 > 0")
32
+ if not remaining_cash.is_finite() or remaining_cash < 0:
33
+ raise ValueError("订单冻结现金必须是有限非负 Decimal")
34
+ if side is OrderSide.BUY and remaining_cash <= 0:
35
+ raise ValueError("买单必须冻结正数现金")
36
+ if side is OrderSide.SELL and remaining_cash != 0:
37
+ raise ValueError("卖单不得冻结现金")
38
+ self.order_id = order_id
39
+ self.instrument_id = instrument_id
40
+ self.side = side
41
+ self._remaining_quantity = remaining_quantity
42
+ self._remaining_cash = remaining_cash
43
+
44
+ @property
45
+ def remaining_quantity(self) -> int:
46
+ return self._remaining_quantity
47
+
48
+ @property
49
+ def remaining_cash(self) -> Decimal:
50
+ return self._remaining_cash
51
+
52
+ def ensure_matches(self, instrument_id: str, side: OrderSide) -> None:
53
+ """保证成交只能消耗自身订单方向和标的对应的冻结资源。"""
54
+ if instrument_id != self.instrument_id or side is not self.side:
55
+ raise ValueError("成交标的或方向与订单冻结资源不一致")
56
+
57
+ def consume(self, quantity: int, cash: Decimal = Decimal("0")) -> None:
58
+ """成交时消耗冻结资源,并保护订单冻结不被透支。"""
59
+ if quantity <= 0 or quantity > self.remaining_quantity:
60
+ raise ValueError("成交数量超过订单剩余冻结数量")
61
+ if not cash.is_finite() or cash < 0:
62
+ raise ValueError("冻结现金消耗必须是有限非负 Decimal")
63
+ if self.side is OrderSide.BUY:
64
+ if cash <= 0 or cash > self.remaining_cash:
65
+ raise ValueError("成交金额超过订单剩余冻结现金")
66
+ elif cash != 0:
67
+ raise ValueError("卖单不得消耗冻结现金")
68
+ self._remaining_quantity -= quantity
69
+ self._remaining_cash -= cash
File without changes
File without changes
@@ -0,0 +1,77 @@
1
+ """
2
+ Portfolio Protocol - Trading Runtime / Order Planning 消费的组合 Port
3
+
4
+ 依赖方向:Portfolio 消费 Order Execution 的 Fill(Fill Rule);Runtime 与
5
+ Strategy 只依赖本 Protocol 与只读 Snapshot。实现(T3 Simulated Portfolio)
6
+ 结构满足即可,跨域不得依赖实现内部。
7
+ """
8
+
9
+ from collections.abc import Mapping
10
+ from datetime import date, datetime
11
+ from decimal import Decimal
12
+ from typing import Protocol, runtime_checkable
13
+
14
+ from quant_core.app.data.schema.corporate_action_schema import CorporateActionEventPayload
15
+ from quant_core.app.order_execution.domain.order_event import Fill
16
+ from quant_core.app.portfolio.ledger_schema import (
17
+ CashLedgerEntry,
18
+ ClosedTrade,
19
+ OrderReservationLedgerEntry,
20
+ PositionLotSnapshot,
21
+ )
22
+ from quant_core.app.portfolio.portfolio_schema import (
23
+ CashSnapshot,
24
+ PortfolioSnapshot,
25
+ PositionSnapshot,
26
+ )
27
+
28
+
29
+ @runtime_checkable
30
+ class IPortfolioUpdate(Protocol):
31
+ """组合变更能力:唯一交易输入是 Fill"""
32
+
33
+ def apply_fill(self, fill: Fill) -> None:
34
+ """应用一次已确认成交(现金/持仓/成本/已实现盈亏)"""
35
+ ...
36
+
37
+ def apply_corporate_action(self, event: CorporateActionEventPayload, at: datetime) -> None:
38
+ """按阶段应用公司行动权益事件。"""
39
+ ...
40
+
41
+ def mark_to_market(self, prices: Mapping[str, Decimal], at: datetime) -> None:
42
+ """按片内收盘价估值并刷新未实现盈亏(价格缺失标的保持上次估值)"""
43
+ ...
44
+
45
+ def settle_trading_day(self, trading_day: date) -> None:
46
+ """交易日边界结算(如新交易日首片释放 T+1 available)"""
47
+ ...
48
+
49
+ def snapshot(self) -> PortfolioSnapshot:
50
+ """当前 point-in-time 只读投影"""
51
+ ...
52
+
53
+
54
+ @runtime_checkable
55
+ class IPortfolioReader(Protocol):
56
+ """组合只读能力(Strategy / Order Planning 的最小依赖面)"""
57
+
58
+ def get_cash(self) -> CashSnapshot:
59
+ """读取可用/冻结/合计资金"""
60
+ ...
61
+
62
+ def get_position(self, instrument_id: str) -> PositionSnapshot | None:
63
+ """读取单标的持仓投影;无持仓返回 None"""
64
+ ...
65
+
66
+
67
+ @runtime_checkable
68
+ class IPortfolioLedger(Protocol):
69
+ """Backtest 只读消费的账本事实能力面。"""
70
+
71
+ def position_lots(self) -> tuple[PositionLotSnapshot, ...]: ...
72
+
73
+ def cash_ledger_entries(self) -> tuple[CashLedgerEntry, ...]: ...
74
+
75
+ def closed_trades(self) -> tuple[ClosedTrade, ...]: ...
76
+
77
+ def reservation_ledger_entries(self) -> tuple[OrderReservationLedgerEntry, ...]: ...
@@ -0,0 +1,16 @@
1
+ """运行账户组合既有更新、读取、预占与账本契约,不公开实现。"""
2
+
3
+ from typing import Protocol
4
+
5
+ from quant_core.app.order_execution.interface.public.execution_account import IExecutionReservation
6
+ from quant_core.app.portfolio.interface.public.portfolio import (
7
+ IPortfolioLedger,
8
+ IPortfolioReader,
9
+ IPortfolioUpdate,
10
+ )
11
+
12
+
13
+ class ISimulationAccount(
14
+ IPortfolioUpdate, IPortfolioReader, IPortfolioLedger, IExecutionReservation, Protocol
15
+ ):
16
+ pass
@@ -0,0 +1,130 @@
1
+ """Portfolio 不可变账本事实与持仓批次投影。"""
2
+
3
+ from datetime import date, datetime
4
+ from decimal import Decimal
5
+ from enum import Enum
6
+
7
+ from pydantic import BaseModel, ConfigDict, Field, field_validator
8
+
9
+ from quant_core.app.data.schema.trading_state_schema import validate_canonical_instrument_id
10
+ from quant_core.app.order_execution.validators import reject_float_amount, validate_identifier
11
+
12
+
13
+ class CashLedgerAccount(str, Enum):
14
+ CASH = "cash"
15
+ FROZEN_CASH = "frozen_cash"
16
+ DIVIDEND_RECEIVABLE = "dividend_receivable"
17
+
18
+
19
+ class CashLedgerEntryType(str, Enum):
20
+ INITIAL_BALANCE = "initial_balance"
21
+ TRADE_GROSS = "trade_gross"
22
+ TRADE_FEE = "trade_fee"
23
+ DIVIDEND_RECEIVABLE = "dividend_receivable"
24
+ DIVIDEND_PAYMENT = "dividend_payment"
25
+ DIVIDEND_TAX = "dividend_tax"
26
+ ORDER_RESERVE = "order_reserve"
27
+ ORDER_RELEASE = "order_release"
28
+
29
+
30
+ class ReservationLedgerAction(str, Enum):
31
+ RESERVE = "reserve"
32
+ CONSUME = "consume"
33
+ RELEASE = "release"
34
+
35
+
36
+ class OrderReservationLedgerEntry(BaseModel):
37
+ """订单冻结资源的 append-only 事实;按 order_id 求和可重建当前冻结。"""
38
+
39
+ model_config = ConfigDict(frozen=True)
40
+
41
+ entry_id: str
42
+ order_id: str
43
+ instrument_id: str
44
+ side: str
45
+ action: ReservationLedgerAction
46
+ cash_delta: Decimal
47
+ quantity_delta: int
48
+ event_time: datetime
49
+
50
+ _validate_entry_id = field_validator("entry_id")(
51
+ classmethod(lambda cls, value: validate_identifier(value, "entry_id"))
52
+ )
53
+ _validate_order_id = field_validator("order_id")(
54
+ classmethod(lambda cls, value: validate_identifier(value, "order_id"))
55
+ )
56
+ _validate_instrument = field_validator("instrument_id")(
57
+ classmethod(lambda cls, value: validate_canonical_instrument_id(value))
58
+ )
59
+ _validate_cash = field_validator("cash_delta", mode="before")(
60
+ classmethod(lambda cls, value: reject_float_amount(value, "cash_delta"))
61
+ )
62
+
63
+
64
+ class PositionLotSnapshot(BaseModel):
65
+ """一笔买入或送股形成的持仓批次当前投影。"""
66
+
67
+ model_config = ConfigDict(frozen=True)
68
+
69
+ lot_id: str
70
+ instrument_id: str
71
+ source_id: str
72
+ acquired_at: datetime
73
+ available_on: date | None
74
+ original_quantity: int = Field(..., gt=0)
75
+ remaining_quantity: int = Field(..., ge=0)
76
+ available_quantity: int = Field(..., ge=0)
77
+ unit_cost: Decimal = Field(..., ge=0)
78
+
79
+ _validate_lot_id = field_validator("lot_id")(
80
+ classmethod(lambda cls, value: validate_identifier(value, "lot_id"))
81
+ )
82
+ _validate_instrument = field_validator("instrument_id")(
83
+ classmethod(lambda cls, value: validate_canonical_instrument_id(value))
84
+ )
85
+ _validate_cost = field_validator("unit_cost", mode="before")(
86
+ classmethod(lambda cls, value: reject_float_amount(value, "unit_cost"))
87
+ )
88
+
89
+
90
+ class CashLedgerEntry(BaseModel):
91
+ """现金或应收股息账户的 append-only 变动事实。"""
92
+
93
+ model_config = ConfigDict(frozen=True)
94
+
95
+ entry_id: str
96
+ account_id: str
97
+ account: CashLedgerAccount
98
+ entry_type: CashLedgerEntryType
99
+ amount: Decimal
100
+ event_time: datetime
101
+ source_key: str
102
+ instrument_id: str | None = None
103
+
104
+ _validate_amount = field_validator("amount", mode="before")(
105
+ classmethod(lambda cls, value: reject_float_amount(value, "amount"))
106
+ )
107
+
108
+
109
+ class ClosedTrade(BaseModel):
110
+ """FIFO 买入批次与卖出 Fill 的不可变平仓配对事实。"""
111
+
112
+ model_config = ConfigDict(frozen=True)
113
+
114
+ trade_id: str
115
+ instrument_id: str
116
+ position_lot_id: str
117
+ buy_source_id: str
118
+ sell_fill_id: str
119
+ quantity: int = Field(..., gt=0)
120
+ opened_at: datetime
121
+ closed_at: datetime
122
+ cost_basis: Decimal = Field(..., ge=0)
123
+ proceeds: Decimal = Field(..., ge=0)
124
+ sell_fees: Decimal = Field(..., ge=0)
125
+ realized_pnl: Decimal
126
+ holding_days: int = Field(..., ge=0)
127
+
128
+ _validate_amounts = field_validator(
129
+ "cost_basis", "proceeds", "sell_fees", "realized_pnl", mode="before"
130
+ )(classmethod(lambda cls, value: reject_float_amount(value, "closed_trade amount")))
@@ -0,0 +1,36 @@
1
+ """账户订阅订单与成交事件;资源冻结和入账统一由 Portfolio 拥有。"""
2
+
3
+ from decimal import Decimal
4
+
5
+ from quant_core.app.order_execution.constants import OrderStatus
6
+ from quant_core.app.order_execution.domain.order_event import Fill, OrderTransition
7
+ from quant_core.app.order_execution.domain.order_value import OrderIntent
8
+ from quant_core.app.portfolio.interface.public.simulation_account import ISimulationAccount
9
+
10
+
11
+ class OrderAccountListener:
12
+ """在 Broker 返回前同步更新账户,不经 Runtime 二次应用成交。"""
13
+
14
+ def __init__(self, account: ISimulationAccount) -> None:
15
+ self._account = account
16
+
17
+ def on_order_pending_new(self, order_id: str, intent: OrderIntent, cash: Decimal) -> bool:
18
+ return self._account.reserve_order(
19
+ order_id,
20
+ intent.instrument_id,
21
+ intent.side,
22
+ intent.quantity,
23
+ cash,
24
+ intent.creation_event_time,
25
+ )
26
+
27
+ def on_trade(self, fill: Fill) -> None:
28
+ self._account.apply_fill(fill)
29
+
30
+ def on_order_update(self, update: OrderTransition) -> None:
31
+ if update.current_status in {
32
+ OrderStatus.FILLED,
33
+ OrderStatus.CANCELLED,
34
+ OrderStatus.EXPIRED,
35
+ }:
36
+ self._account.release_order_reservation(update.order_id, update.event_time)
@@ -0,0 +1,21 @@
1
+ """Portfolio 所属域的模拟账户组装入口。"""
2
+
3
+ from datetime import datetime
4
+ from decimal import Decimal
5
+
6
+ from quant_core.app.order_execution.interface.public.order_events import IOrderEventListener
7
+ from quant_core.app.portfolio.interface.public.simulation_account import ISimulationAccount
8
+ from quant_core.app.portfolio.order_account_listener import OrderAccountListener
9
+ from quant_core.app.portfolio.simulated_portfolio import SimulatedPortfolio
10
+
11
+
12
+ def build_simulation_account(
13
+ account_id: str, initial_cash: Decimal, start: datetime
14
+ ) -> ISimulationAccount:
15
+ """返回组合账户能力,不向应用服务暴露 SimulatedPortfolio。"""
16
+ return SimulatedPortfolio(account_id, initial_cash, start)
17
+
18
+
19
+ def build_order_account_listener(account: ISimulationAccount) -> IOrderEventListener:
20
+ """向订单事件总线提供账户监听能力。"""
21
+ return OrderAccountListener(account)