powerquant-cli 0.2.7__tar.gz → 0.2.10__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (466) hide show
  1. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/PKG-INFO +26 -3
  2. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/README.md +24 -2
  3. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/pqdata/client.py +63 -13
  4. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/pqdata/exceptions.py +6 -2
  5. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/pqdata/schema/query_schema.py +1 -0
  6. powerquant_cli-0.2.10/bundled/pqdata/schema/snapshot_schema.py +50 -0
  7. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/full_market_screen.py +4 -4
  8. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/pyproject.toml +3 -3
  9. powerquant_cli-0.2.10/src/quant_cli/app/agent_resources/cli/agent_resource_cli.py +70 -0
  10. powerquant_cli-0.2.10/src/quant_cli/app/agent_resources/interface/public/agent_resource_sync.py +14 -0
  11. powerquant_cli-0.2.10/src/quant_cli/app/agent_resources/repository/agent_resource_repository.py +57 -0
  12. powerquant_cli-0.2.10/src/quant_cli/app/agent_resources/schema/agent_resource_schema.py +89 -0
  13. powerquant_cli-0.2.10/src/quant_cli/app/agent_resources/service/agent_resource_service.py +279 -0
  14. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/backtest/cli/local_backtest_cli.py +17 -13
  15. powerquant_cli-0.2.10/src/quant_cli/app/backtest/service/backtest_application_service.py +29 -0
  16. powerquant_cli-0.2.10/src/quant_cli/app/cli_dependency.py +11 -0
  17. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/data/cli/data_cli.py +8 -6
  18. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/data/data_dependency.py +1 -4
  19. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/data/service/bar_cache_service.py +50 -97
  20. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/data/service/dataset_load_service.py +7 -9
  21. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/data/service/dataset_prepare_service.py +23 -6
  22. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/factor/cli/factor_definition_cli.py +6 -4
  23. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/factor/cli/local_factor_cli.py +18 -13
  24. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/factor/cli/local_selection_cli.py +10 -19
  25. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/factor/local_factor_dependency.py +1 -1
  26. powerquant_cli-0.2.10/src/quant_cli/app/factor/service/factor_application_service.py +41 -0
  27. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/job/cli/local_job_cli.py +9 -9
  28. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/quant_cli.py +33 -4
  29. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/research/cli/local_research_cli.py +20 -17
  30. powerquant_cli-0.2.10/src/quant_cli/app/research/service/research_application_service.py +34 -0
  31. powerquant_cli-0.2.10/src/quant_cli/app/strategy/cli/__init__.py +0 -0
  32. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/strategy/cli/strategy_cli.py +11 -10
  33. powerquant_cli-0.2.10/src/quant_cli/app/system/__init__.py +0 -0
  34. powerquant_cli-0.2.10/src/quant_cli/app/system/cli/__init__.py +0 -0
  35. powerquant_cli-0.2.10/src/quant_cli/app/system/cli/config_cli.py +50 -0
  36. powerquant_cli-0.2.10/src/quant_cli/app/system/cli/system_cli.py +66 -0
  37. powerquant_cli-0.2.10/src/quant_cli/app/system/interface/__init__.py +0 -0
  38. powerquant_cli-0.2.10/src/quant_cli/app/system/interface/package_updater.py +9 -0
  39. powerquant_cli-0.2.10/src/quant_cli/app/system/service/__init__.py +0 -0
  40. powerquant_cli-0.2.10/src/quant_cli/app/system/service/bootstrap_service.py +57 -0
  41. powerquant_cli-0.2.10/src/quant_cli/app/system/service/connection_service.py +39 -0
  42. powerquant_cli-0.2.10/src/quant_cli/app/system/service/upgrade_service.py +41 -0
  43. powerquant_cli-0.2.10/src/quant_cli/application_container.py +63 -0
  44. powerquant_cli-0.2.10/src/quant_cli/application_settings.py +19 -0
  45. powerquant_cli-0.2.10/src/quant_cli/common/__init__.py +0 -0
  46. powerquant_cli-0.2.10/src/quant_cli/common/application_errors.py +8 -0
  47. powerquant_cli-0.2.10/src/quant_cli/common/command_error_handler.py +53 -0
  48. powerquant_cli-0.2.10/src/quant_cli/common/command_help.py +45 -0
  49. powerquant_cli-0.2.10/src/quant_cli/common/database/__init__.py +0 -0
  50. powerquant_cli-0.2.10/src/quant_cli/common/filesystem.py +73 -0
  51. powerquant_cli-0.2.10/src/quant_cli/common/hashing.py +5 -0
  52. powerquant_cli-0.2.10/src/quant_cli/common/http/__init__.py +0 -0
  53. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/common/http/definition_client.py +27 -1
  54. powerquant_cli-0.2.10/src/quant_cli/common/operation_error.py +10 -0
  55. powerquant_cli-0.2.10/src/quant_cli/common/package_update_worker.py +145 -0
  56. powerquant_cli-0.2.10/src/quant_cli/common/package_updater.py +211 -0
  57. powerquant_cli-0.2.10/src/quant_cli/common/utils/__init__.py +0 -0
  58. powerquant_cli-0.2.10/src/quant_cli/common/utils/cli_utils.py +88 -0
  59. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/config/connection_config.py +6 -7
  60. powerquant_cli-0.2.10/src/quant_cli/resources/agent_hint.md +7 -0
  61. powerquant_cli-0.2.10/src/quant_cli/resources/skills/pq-bootstrap/SKILL.md +49 -0
  62. powerquant_cli-0.2.10/src/quant_cli/resources/skills/pq-bootstrap/references/resources.md +9 -0
  63. powerquant_cli-0.2.10/src/quant_cli/resources/skills/pq-data-operations/SKILL.md +37 -0
  64. powerquant_cli-0.2.10/src/quant_cli/resources/skills/pq-research/SKILL.md +47 -0
  65. powerquant_cli-0.2.10/tests/__init__.py +0 -0
  66. powerquant_cli-0.2.10/tests/integration/__init__.py +0 -0
  67. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/integration/test_local_quant_storage.py +1 -1
  68. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/integration/test_local_selection.py +4 -4
  69. powerquant_cli-0.2.10/tests/unit/test_agent_install.py +131 -0
  70. powerquant_cli-0.2.10/tests/unit/test_agent_json.py +26 -0
  71. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_bar_cache.py +12 -8
  72. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_connection_config.py +13 -1
  73. powerquant_cli-0.2.10/tests/unit/test_definition_errors.py +59 -0
  74. powerquant_cli-0.2.10/tests/unit/test_package_upgrade.py +260 -0
  75. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/uv.lock +50 -2
  76. powerquant_cli-0.2.7/src/quant_cli/app/config/__init__.py +0 -1
  77. powerquant_cli-0.2.7/src/quant_cli/app/config/config_cli.py +0 -71
  78. powerquant_cli-0.2.7/src/quant_cli/common/utils/cli_utils.py +0 -37
  79. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/.env.example +0 -0
  80. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/.gitignore +0 -0
  81. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/LICENSE +0 -0
  82. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/pqdata/__init__.py +0 -0
  83. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/pqdata/download.py +0 -0
  84. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/pqdata/schema/__init__.py +0 -0
  85. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/pqdata/schema/adjustment_schema.py +0 -0
  86. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/pqdata/schema/bar_content_schema.py +0 -0
  87. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/pqdata/schema/bar_schema.py +0 -0
  88. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/pqdata/schema/corporate_action_schema.py +0 -0
  89. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/pqdata/schema/history_schema.py +0 -0
  90. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/pqdata/schema/pit_daily_window.py +0 -0
  91. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/pqdata/schema/quote_schema.py +0 -0
  92. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/pqdata/schema/reference_schema.py +0 -0
  93. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/pqdata/schema/reliability_schema.py +0 -0
  94. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/__init__.py +0 -0
  95. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/SPEC.md +0 -0
  96. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/__init__.py +0 -0
  97. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/backtest/SPEC.md +0 -0
  98. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/backtest/__init__.py +0 -0
  99. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/backtest/backtest_input_schema.py +0 -0
  100. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/backtest/backtest_run.py +0 -0
  101. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/backtest/data_guard.py +0 -0
  102. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/backtest/historical_clock.py +0 -0
  103. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/backtest/legacy_result_schema.py +0 -0
  104. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/backtest/metrics.py +0 -0
  105. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/backtest/performance_report.py +0 -0
  106. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/backtest/report_schema.py +0 -0
  107. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/backtest/schema.py +0 -0
  108. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/backtest/service/__init__.py +0 -0
  109. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/backtest/service/backtest_execution_service.py +0 -0
  110. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/__init__.py +0 -0
  111. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/constants.py +0 -0
  112. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/domain/__init__.py +0 -0
  113. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/domain/trading_quantity_value.py +0 -0
  114. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/exceptions.py +0 -0
  115. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/interface/__init__.py +0 -0
  116. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/interface/adjustment_factor_query.py +0 -0
  117. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/interface/market_data_query.py +0 -0
  118. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/interface/market_data_verification.py +0 -0
  119. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/interface/market_event_source.py +0 -0
  120. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/interface/market_revision_query.py +0 -0
  121. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/interface/market_runtime_repository.py +0 -0
  122. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/interface/market_time_slice_source.py +0 -0
  123. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/repository/__init__.py +0 -0
  124. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/schema/__init__.py +0 -0
  125. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/schema/adjustment_schema.py +0 -0
  126. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/schema/corporate_action_schema.py +0 -0
  127. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/schema/event_schema.py +0 -0
  128. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/schema/exchange_operating_state.py +0 -0
  129. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/schema/exchange_state_schema.py +0 -0
  130. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/schema/history_schema.py +0 -0
  131. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/schema/instrument_identity.py +0 -0
  132. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/schema/market_schema.py +0 -0
  133. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/schema/pit_daily_window.py +0 -0
  134. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/schema/quote_schema.py +0 -0
  135. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/schema/reliability_schema.py +0 -0
  136. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/schema/snapshot_schema.py +0 -0
  137. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/schema/trading_state_schema.py +0 -0
  138. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/service/__init__.py +0 -0
  139. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/service/calendar_coverage_service.py +0 -0
  140. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/service/prepared_data_verification_service.py +0 -0
  141. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/service/prepared_market_service.py +0 -0
  142. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/data/service/price_adjustment_service.py +0 -0
  143. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/LICENSE.vnpy +0 -0
  144. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/__init__.py +0 -0
  145. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/builtin/__init__.py +0 -0
  146. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/builtin/alpha101_recipe.py +0 -0
  147. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/builtin/alpha158_recipe.py +0 -0
  148. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/builtin/factor_recipe_catalog.py +0 -0
  149. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/computation/__init__.py +0 -0
  150. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/computation/factor_batch_evaluator.py +0 -0
  151. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/computation/factor_expression.py +0 -0
  152. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/computation/factor_source_loader.py +0 -0
  153. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/computation/operators/__init__.py +0 -0
  154. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/computation/operators/arithmetic_operator.py +0 -0
  155. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/computation/operators/cross_section_operator.py +0 -0
  156. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/computation/operators/time_series_operator.py +0 -0
  157. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/computation/panel_evaluator.py +0 -0
  158. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/computation/panel_expression.py +0 -0
  159. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/computation/python_factor_executor.py +0 -0
  160. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/computation/universe_filter.py +0 -0
  161. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/constants.py +0 -0
  162. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/exceptions.py +0 -0
  163. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/factor_dependency.py +0 -0
  164. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/interface/__init__.py +0 -0
  165. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/interface/factor_compute.py +0 -0
  166. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/interface/factor_execution.py +0 -0
  167. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/interface/factor_local_data.py +0 -0
  168. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/interface/factor_panel_compute.py +0 -0
  169. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/interface/factor_panel_input.py +0 -0
  170. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/interface/factor_query_store.py +0 -0
  171. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/interface/public/__init__.py +0 -0
  172. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/interface/public/factor_diagnostics.py +0 -0
  173. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/interface/public/factor_exposure_query.py +0 -0
  174. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/interface/public/factor_local.py +0 -0
  175. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/interface/public/factor_query.py +0 -0
  176. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/interface/public/factor_selection.py +0 -0
  177. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/model/__init__.py +0 -0
  178. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/repository/__init__.py +0 -0
  179. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/schema/__init__.py +0 -0
  180. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/schema/diagnostic_types.py +0 -0
  181. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/schema/factor_artifact_schema.py +0 -0
  182. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/schema/factor_computation_schema.py +0 -0
  183. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/schema/factor_compute_request.py +0 -0
  184. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/schema/factor_contract.py +0 -0
  185. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/schema/factor_input_schema.py +0 -0
  186. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/schema/factor_panel.py +0 -0
  187. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/schema/factor_publication_schema.py +0 -0
  188. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/schema/factor_query_result_schema.py +0 -0
  189. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/schema/factor_result_schema.py +0 -0
  190. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/schema/local_factor_schema.py +0 -0
  191. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/schema/panel_policy.py +0 -0
  192. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/schema/selection_report.py +0 -0
  193. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/schema/selection_types.py +0 -0
  194. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/service/__init__.py +0 -0
  195. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/service/factor_compute_service.py +0 -0
  196. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/service/factor_diagnostic_runner.py +0 -0
  197. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/service/factor_diagnostics_service.py +0 -0
  198. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/service/factor_exposure_service.py +0 -0
  199. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/service/factor_input_service.py +0 -0
  200. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/service/factor_local_execution_service.py +0 -0
  201. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/service/factor_panel_service.py +0 -0
  202. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/service/factor_runtime_service.py +0 -0
  203. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/service/factor_selection_runner.py +0 -0
  204. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/service/published_factor_execution_service.py +0 -0
  205. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/service/selection_service.py +0 -0
  206. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/factor/visibility.py +0 -0
  207. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/opportunity/SPEC.md +0 -0
  208. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/opportunity/__init__.py +0 -0
  209. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/SPEC.md +0 -0
  210. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/__init__.py +0 -0
  211. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/bar_matcher.py +0 -0
  212. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/constants.py +0 -0
  213. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/domain/__init__.py +0 -0
  214. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/domain/execution_batch.py +0 -0
  215. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/domain/order_entity.py +0 -0
  216. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/domain/order_event.py +0 -0
  217. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/domain/order_policy.py +0 -0
  218. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/domain/order_value.py +0 -0
  219. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/fee_model.py +0 -0
  220. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/interface/__init__.py +0 -0
  221. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/interface/order_account.py +0 -0
  222. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/interface/order_trading_rules.py +0 -0
  223. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/interface/public/__init__.py +0 -0
  224. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/interface/public/execution_account.py +0 -0
  225. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/interface/public/order_events.py +0 -0
  226. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/interface/public/order_execution.py +0 -0
  227. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/interface/public/order_runtime.py +0 -0
  228. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/interface/public/order_submission.py +0 -0
  229. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/order_event_bus.py +0 -0
  230. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/order_execution_dependency.py +0 -0
  231. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/order_submission_service.py +0 -0
  232. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/schema/__init__.py +0 -0
  233. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/schema/order_request_schema.py +0 -0
  234. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/simulation_broker.py +0 -0
  235. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/slippage_model.py +0 -0
  236. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/tradability_policy.py +0 -0
  237. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/order_execution/validators.py +0 -0
  238. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/portfolio/SPEC.md +0 -0
  239. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/portfolio/__init__.py +0 -0
  240. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/portfolio/domain/__init__.py +0 -0
  241. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/portfolio/domain/entitlement_entity.py +0 -0
  242. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/portfolio/domain/portfolio_entity.py +0 -0
  243. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/portfolio/domain/portfolio_event.py +0 -0
  244. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/portfolio/domain/portfolio_value.py +0 -0
  245. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/portfolio/domain/position_entity.py +0 -0
  246. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/portfolio/domain/reservation_entity.py +0 -0
  247. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/portfolio/interface/__init__.py +0 -0
  248. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/portfolio/interface/public/__init__.py +0 -0
  249. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/portfolio/interface/public/portfolio.py +0 -0
  250. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/portfolio/interface/public/simulation_account.py +0 -0
  251. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/portfolio/ledger_schema.py +0 -0
  252. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/portfolio/order_account_listener.py +0 -0
  253. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/portfolio/portfolio_dependency.py +0 -0
  254. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/portfolio/portfolio_schema.py +0 -0
  255. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/portfolio/simulated_portfolio.py +0 -0
  256. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/research/SPEC.md +0 -0
  257. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/research/__init__.py +0 -0
  258. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/research/adapter/__init__.py +0 -0
  259. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/research/adapter/market_label_query.py +0 -0
  260. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/research/interface/__init__.py +0 -0
  261. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/research/interface/research_dataset.py +0 -0
  262. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/research/interface/research_evaluation.py +0 -0
  263. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/research/schema/__init__.py +0 -0
  264. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/research/schema/comparison_schema.py +0 -0
  265. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/research/schema/dataset_schema.py +0 -0
  266. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/research/schema/research_schema.py +0 -0
  267. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/research/service/__init__.py +0 -0
  268. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/research/service/research_dataset_service.py +0 -0
  269. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/research/service/research_evaluation_service.py +0 -0
  270. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/research/service/research_service.py +0 -0
  271. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/SPEC.md +0 -0
  272. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/__init__.py +0 -0
  273. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/constants.py +0 -0
  274. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/exceptions.py +0 -0
  275. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/interface/__init__.py +0 -0
  276. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/interface/public/__init__.py +0 -0
  277. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/interface/public/portfolio_construction.py +0 -0
  278. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/interface/public/strategy.py +0 -0
  279. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/interface/public/strategy_market_query.py +0 -0
  280. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/interface/public/strategy_portfolio_reader.py +0 -0
  281. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/interface/strategy_factor_reader.py +0 -0
  282. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/interface/strategy_order_reader.py +0 -0
  283. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/schema/__init__.py +0 -0
  284. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/schema/portfolio_schema.py +0 -0
  285. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/schema/portfolio_target.py +0 -0
  286. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/schema/python_strategy_schema.py +0 -0
  287. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/schema/screener_schema.py +0 -0
  288. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/schema/signal_schema.py +0 -0
  289. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/schema/strategy_publication_schema.py +0 -0
  290. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/schema/strategy_schema.py +0 -0
  291. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/service/__init__.py +0 -0
  292. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/service/factor_top_n_strategy.py +0 -0
  293. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/service/portfolio_construction_service.py +0 -0
  294. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/service/python_strategy_service.py +0 -0
  295. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/service/screener_service.py +0 -0
  296. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/service/store_factor_reader.py +0 -0
  297. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/service/strategy_market_view.py +0 -0
  298. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/service/strategy_runtime_service.py +0 -0
  299. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/service/strategy_scheduler.py +0 -0
  300. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/strategies/__init__.py +0 -0
  301. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/strategies/momentum_volume_breakout.py +0 -0
  302. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/strategy_context.py +0 -0
  303. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/strategy/strategy_dependency.py +0 -0
  304. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/trading_runtime/SPEC.md +0 -0
  305. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/trading_runtime/__init__.py +0 -0
  306. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/trading_runtime/domain/__init__.py +0 -0
  307. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/trading_runtime/replay/__init__.py +0 -0
  308. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/trading_runtime/replay/daily_state_expand.py +0 -0
  309. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/trading_runtime/replay/exchange_state_resolver.py +0 -0
  310. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/trading_runtime/replay/market_runtime_service.py +0 -0
  311. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/trading_runtime/replay/market_state_resolver.py +0 -0
  312. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/trading_runtime/runtime_ports.py +0 -0
  313. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/trading_runtime/runtime_schema.py +0 -0
  314. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/trading_runtime/runtime_session.py +0 -0
  315. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/trading_runtime/strategy_portfolio_adapter.py +0 -0
  316. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/trading_runtime/trading_rule_book.py +0 -0
  317. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/app/trading_runtime/trading_rule_query.py +0 -0
  318. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/common/__init__.py +0 -0
  319. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/common/exceptions/__init__.py +0 -0
  320. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/common/exceptions/base.py +0 -0
  321. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/bundled/quant_core/common/local_run.py +0 -0
  322. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/cached_factor_screen.py +0 -0
  323. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/factors/ma_close_10.py +0 -0
  324. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/factors/max_drawdown_20d.py +0 -0
  325. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/factors/momentum_20d.py +0 -0
  326. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/factors/multi_intraday_screen.py +0 -0
  327. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/factors/risk_adjusted_momentum_20d.py +0 -0
  328. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/factors/volume_ratio_5d.py +0 -0
  329. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/factors/volume_weighted_close_pressure.py +0 -0
  330. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/local_quant_validation.py +0 -0
  331. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/published_definition_validation.py +0 -0
  332. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/research/factor_pit_coverage.py +0 -0
  333. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/research/ipo_first_day.py +0 -0
  334. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/selection/README.md +0 -0
  335. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/selection/backtest.json +0 -0
  336. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/selection/buy_hold.py +0 -0
  337. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/selection/compute.json +0 -0
  338. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/selection/prepare.json +0 -0
  339. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/selection/select.json +0 -0
  340. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/strategies/bar_roundtrip.py +0 -0
  341. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/strategies/buy_and_hold.py +0 -0
  342. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/strategies/contrarian_timing.py +0 -0
  343. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/strategies/factor_gate_vwap.py +0 -0
  344. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/strategies/ipo_next_day_vwap.py +0 -0
  345. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/strategies/momentum_timing.py +0 -0
  346. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/strategies/monthly_equal_weight.py +0 -0
  347. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/strategies/session_roundtrip.py +0 -0
  348. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/strategies/trend_drawdown_guard.py +0 -0
  349. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/strategies/weekly_risk_adjusted_rotation.py +0 -0
  350. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/examples/unified_snapshot_validation.py +0 -0
  351. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/hatch_build.py +0 -0
  352. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/licenses/LICENSE.vnpy +0 -0
  353. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/__init__.py +0 -0
  354. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/api.py +0 -0
  355. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/__init__.py +0 -0
  356. {powerquant_cli-0.2.7/src/quant_cli/app/backtest → powerquant_cli-0.2.10/src/quant_cli/app/agent_resources}/__init__.py +0 -0
  357. {powerquant_cli-0.2.7/src/quant_cli/app/backtest → powerquant_cli-0.2.10/src/quant_cli/app/agent_resources}/cli/__init__.py +0 -0
  358. {powerquant_cli-0.2.7/src/quant_cli/app/backtest/repository → powerquant_cli-0.2.10/src/quant_cli/app/agent_resources/interface}/__init__.py +0 -0
  359. {powerquant_cli-0.2.7/src/quant_cli/app/backtest/service → powerquant_cli-0.2.10/src/quant_cli/app/agent_resources/interface/public}/__init__.py +0 -0
  360. {powerquant_cli-0.2.7/src/quant_cli/app/data → powerquant_cli-0.2.10/src/quant_cli/app/agent_resources/repository}/__init__.py +0 -0
  361. {powerquant_cli-0.2.7/src/quant_cli/app/data/cli → powerquant_cli-0.2.10/src/quant_cli/app/agent_resources/schema}/__init__.py +0 -0
  362. {powerquant_cli-0.2.7/src/quant_cli/app/data/repository → powerquant_cli-0.2.10/src/quant_cli/app/agent_resources/service}/__init__.py +0 -0
  363. {powerquant_cli-0.2.7/src/quant_cli/app/data/schema → powerquant_cli-0.2.10/src/quant_cli/app/backtest}/__init__.py +0 -0
  364. {powerquant_cli-0.2.7/src/quant_cli/app/data/service → powerquant_cli-0.2.10/src/quant_cli/app/backtest/cli}/__init__.py +0 -0
  365. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/backtest/local_backtest_dependency.py +0 -0
  366. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/backtest/local_backtest_schema.py +0 -0
  367. {powerquant_cli-0.2.7/src/quant_cli/app/factor → powerquant_cli-0.2.10/src/quant_cli/app/backtest/repository}/__init__.py +0 -0
  368. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/backtest/repository/backtest_local_repository.py +0 -0
  369. {powerquant_cli-0.2.7/src/quant_cli/app/factor/cli → powerquant_cli-0.2.10/src/quant_cli/app/backtest/service}/__init__.py +0 -0
  370. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/backtest/service/local_backtest_service.py +0 -0
  371. {powerquant_cli-0.2.7/src/quant_cli/app/factor/interface → powerquant_cli-0.2.10/src/quant_cli/app/data}/__init__.py +0 -0
  372. {powerquant_cli-0.2.7/src/quant_cli/app/factor/repository → powerquant_cli-0.2.10/src/quant_cli/app/data/cli}/__init__.py +0 -0
  373. {powerquant_cli-0.2.7/src/quant_cli/app/factor/service → powerquant_cli-0.2.10/src/quant_cli/app/data/repository}/__init__.py +0 -0
  374. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/data/repository/parquet_repository.py +0 -0
  375. {powerquant_cli-0.2.7/src/quant_cli/app/job → powerquant_cli-0.2.10/src/quant_cli/app/data/schema}/__init__.py +0 -0
  376. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/data/schema/dataset_audit_schema.py +0 -0
  377. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/data/schema/dataset_request_schema.py +0 -0
  378. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/data/schema/parquet_file_schema.py +0 -0
  379. {powerquant_cli-0.2.7/src/quant_cli/app/job/cli → powerquant_cli-0.2.10/src/quant_cli/app/data/service}/__init__.py +0 -0
  380. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/data/service/dataset_audit_service.py +0 -0
  381. {powerquant_cli-0.2.7/src/quant_cli/app/job/schema → powerquant_cli-0.2.10/src/quant_cli/app/factor}/__init__.py +0 -0
  382. {powerquant_cli-0.2.7/src/quant_cli/app/job/service → powerquant_cli-0.2.10/src/quant_cli/app/factor/cli}/__init__.py +0 -0
  383. {powerquant_cli-0.2.7/src/quant_cli/app/research → powerquant_cli-0.2.10/src/quant_cli/app/factor/interface}/__init__.py +0 -0
  384. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/factor/interface/local_selection_store.py +0 -0
  385. {powerquant_cli-0.2.7/src/quant_cli/app/research/cli → powerquant_cli-0.2.10/src/quant_cli/app/factor/repository}/__init__.py +0 -0
  386. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/factor/repository/factor_local_repository.py +0 -0
  387. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/factor/repository/selection_local_repository.py +0 -0
  388. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/factor/schema/local_selection_schema.py +0 -0
  389. {powerquant_cli-0.2.7/src/quant_cli/app/research/repository → powerquant_cli-0.2.10/src/quant_cli/app/factor/service}/__init__.py +0 -0
  390. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/factor/service/factor_data_prepare_service.py +0 -0
  391. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/factor/service/local_factor_query_service.py +0 -0
  392. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/factor/service/local_factor_service.py +0 -0
  393. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/factor/service/local_selection_service.py +0 -0
  394. {powerquant_cli-0.2.7/src/quant_cli/app/research/schema → powerquant_cli-0.2.10/src/quant_cli/app/job}/__init__.py +0 -0
  395. {powerquant_cli-0.2.7/src/quant_cli/app/research/service → powerquant_cli-0.2.10/src/quant_cli/app/job/cli}/__init__.py +0 -0
  396. {powerquant_cli-0.2.7/src/quant_cli/app/strategy → powerquant_cli-0.2.10/src/quant_cli/app/job/schema}/__init__.py +0 -0
  397. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/job/schema/local_job_schema.py +0 -0
  398. {powerquant_cli-0.2.7/src/quant_cli/app/strategy/cli → powerquant_cli-0.2.10/src/quant_cli/app/job/service}/__init__.py +0 -0
  399. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/job/service/local_job_service.py +0 -0
  400. {powerquant_cli-0.2.7/src/quant_cli/common → powerquant_cli-0.2.10/src/quant_cli/app/research}/__init__.py +0 -0
  401. {powerquant_cli-0.2.7/src/quant_cli/common/database → powerquant_cli-0.2.10/src/quant_cli/app/research/cli}/__init__.py +0 -0
  402. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/research/local_research_dependency.py +0 -0
  403. {powerquant_cli-0.2.7/src/quant_cli/common/http → powerquant_cli-0.2.10/src/quant_cli/app/research/repository}/__init__.py +0 -0
  404. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/research/repository/research_local_repository.py +0 -0
  405. {powerquant_cli-0.2.7/src/quant_cli/common/utils → powerquant_cli-0.2.10/src/quant_cli/app/research/schema}/__init__.py +0 -0
  406. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/research/schema/local_research_schema.py +0 -0
  407. {powerquant_cli-0.2.7/tests → powerquant_cli-0.2.10/src/quant_cli/app/research/service}/__init__.py +0 -0
  408. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/research/service/local_research_execution_service.py +0 -0
  409. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/app/research/service/local_research_service.py +0 -0
  410. {powerquant_cli-0.2.7/tests/integration → powerquant_cli-0.2.10/src/quant_cli/app/strategy}/__init__.py +0 -0
  411. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/common/constants.py +0 -0
  412. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/common/database/duckdb_connection.py +0 -0
  413. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/common/utils/platform_utils.py +0 -0
  414. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/common/utils/runtime_environment.py +0 -0
  415. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/src/quant_cli/config/__init__.py +0 -0
  416. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/conftest.py +0 -0
  417. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/factor_fixtures.py +0 -0
  418. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/__init__.py +0 -0
  419. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_alpha_backtest_reports.py +0 -0
  420. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_alpha_identity.py +0 -0
  421. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_alpha_market_input.py +0 -0
  422. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_alpha_research.py +0 -0
  423. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_alpha_top_n.py +0 -0
  424. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_backtest_run_result.py +0 -0
  425. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_coarse_execution_capability.py +0 -0
  426. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_corporate_action_replay.py +0 -0
  427. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_d1_replay_execution_chain.py +0 -0
  428. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_daily_state_expand.py +0 -0
  429. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_daily_state_snapshot.py +0 -0
  430. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_daily_vwap_execution.py +0 -0
  431. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_data_guard.py +0 -0
  432. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_dataset_audit.py +0 -0
  433. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_domain_dependency_boundaries.py +0 -0
  434. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_domain_interface_boundary.py +0 -0
  435. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_exchange_state_execution.py +0 -0
  436. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_exchange_state_replay.py +0 -0
  437. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_exchange_state_resolver.py +0 -0
  438. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_exchange_state_schema.py +0 -0
  439. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_factor_contract.py +0 -0
  440. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_factor_diagnostic_runner.py +0 -0
  441. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_factor_diagnostics.py +0 -0
  442. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_factor_expression.py +0 -0
  443. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_factor_local_runner.py +0 -0
  444. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_factor_runtime_service.py +0 -0
  445. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_factor_selection.py +0 -0
  446. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_factor_selection_runner.py +0 -0
  447. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_ipo_vwap_study.py +0 -0
  448. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_local_quant_boundary.py +0 -0
  449. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_market_replay.py +0 -0
  450. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_market_trading_state.py +0 -0
  451. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_order_domain.py +0 -0
  452. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_order_submission.py +0 -0
  453. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_portfolio_construction.py +0 -0
  454. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_portfolio_contracts.py +0 -0
  455. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_python_strategy_runtime.py +0 -0
  456. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_replay_state_boundaries.py +0 -0
  457. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_risk_adjusted_strategy_example.py +0 -0
  458. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_simulated_order_execution.py +0 -0
  459. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_simulated_portfolio.py +0 -0
  460. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_store_factor_reader.py +0 -0
  461. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_strategy_adjusted_view.py +0 -0
  462. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_strategy_domain.py +0 -0
  463. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_strategy_lifecycle.py +0 -0
  464. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_tradability_policy.py +0 -0
  465. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_trading_runtime_contracts.py +0 -0
  466. {powerquant_cli-0.2.7 → powerquant_cli-0.2.10}/tests/unit/test_trading_runtime_session.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: powerquant-cli
3
- Version: 0.2.7
3
+ Version: 0.2.10
4
4
  Summary: Power Quant local research CLI
5
5
  Project-URL: Repository, https://github.com/Kepler452Byte/power-quant
6
6
  License-Expression: LicenseRef-PowerQuant-Proprietary AND MIT
@@ -14,6 +14,7 @@ Requires-Dist: numpy<3,>=2
14
14
  Requires-Dist: pandas<4,>=3
15
15
  Requires-Dist: polars<2,>=1.36
16
16
  Requires-Dist: pydantic<3,>=2.5
17
+ Requires-Dist: pyyaml<7,>=6
17
18
  Requires-Dist: scipy<2,>=1.17
18
19
  Requires-Dist: typer>=0.27.2
19
20
  Requires-Dist: tzdata>=2026.3
@@ -51,7 +52,7 @@ pq config show
51
52
 
52
53
  家庭 LAN 可配置 `http://192.168.8.142:18026/market/api/v1`;公网 IP 临时入口为 `http://82.157.167.33/market/api/v1`。公网 HTTP 会明文传输 Token,只适合已明确接受风险的临时接入;长期公网访问使用可信 HTTPS 或 SSH/WireGuard 加密链路。直接使用 `https://82.157.167.33` 与现有域名证书不匹配。
53
54
 
54
- 配置保存在当前系统用户的 `~/.powerquant/config.json`,与工作目录无关,不自动加载 `.env`。这是本地明文配置:POSIX 新目录权限 700、文件权限 600;Windows 依赖用户目录 ACL,不声称加密存储。不要提交或分享该文件。
55
+ 配置保存在当前系统用户的 `~/.powerquant/config.yml`,与工作目录无关,不自动加载 `.env`。这是本地明文配置:POSIX 新目录权限 700、文件权限 600;Windows 依赖用户目录 ACL,不声称加密存储。不要提交或分享该文件。
55
56
 
56
57
  每项配置按环境变量 > 用户文件 > 默认值解析。默认地址为 `http://localhost:8002/api/v1`,默认 Token 为空。环境变量只影响当前终端及其启动的子进程,不改文件;显式空 Token 环境变量会覆盖已保存密钥。
57
58
 
@@ -77,10 +78,32 @@ cd powerquant-examples/selection
77
78
  pq data prepare --config prepare.json
78
79
  ```
79
80
 
80
- 按实际覆盖调整 prepare.json 的股票和日期,将返回 manifest_path 写入 compute.json、select.json;按示例 README 执行 compute、select 和 backtest。不同使用目的的快照须分别通过完整性检查。
81
+ 按实际覆盖调整 prepare.json 的股票和日期,将返回的 data.manifest_path 写入 compute.json、select.json;按示例 README 执行 compute、select 和 backtest。不同使用目的的快照须分别通过完整性检查。
81
82
 
82
83
  密钥到期或撤销后在线准备会失败,已下载快照仍可离线使用。行情密钥不用于定义发布;发布定义另使用 PQ_QUANT_URL/PQ_QUANT_TOKEN。默认本地目录为 ~/.powerquant。
83
84
 
85
+ ## Agent 使用
86
+
87
+ 命令结果统一输出 JSON `{status,data}`;错误以 JSON 写入 stderr,保留业务错误码、消息和 request_id,并返回非零退出码。
88
+
89
+ ```sh
90
+ pq --version
91
+ pq skill list
92
+ pq skill show pq-bootstrap
93
+ pq skill check
94
+ pq init
95
+ ```
96
+
97
+ `pq init` 先返回安装计划。使用返回的 `data.expected_plan` 执行 `pq init --confirm --expected-plan <expected_plan>`,默认安装到 Codex 的 `~/.agents/skills` 和 Claude Code 的 `~/.claude/skills`。可用 `--agent codex|claude|both` 选择客户端,或用 `--skills-dir` 指定项目目录。Hint 仅写入显式提供的 `--hint-file`,保留受管块外的内容。
98
+
99
+ 没有 Token 也可以初始化;需要连接行情时,按 bootstrap Skill 申请权限并通过 `pq config token` 安全录入。行情运维通过 PQData API/MCP 提交任务。
100
+
101
+ `pq upgrade` 先预览,再用 `--confirm --expected-plan <expected_plan>` 启动后台升级;通过 `pq agent upgrade-status <operation_id>` 查询结果。升级沿用 uv tool 或 pipx 安装渠道,并同步已登记的资源目录。`pq upgrade --skip-package` 仅同步资源。独立资源同步使用 `pq agent sync`,同样先预览再确认。
102
+
103
+ ## 依赖生命周期
104
+
105
+ ApplicationContainer 接收 ApplicationSettings,按需组装明确的因子、回测、研究应用 Service,CLI 从 ctx.obj 获取。Service 依赖由构造函数显式传入;不维护通用 Repository 缓存、不查询全局容器、不在缺少上下文时静默创建容器。MarketClient 按需创建并由调用方 async with 关闭,本地 Repository 使用短事务。配置、帮助和资源查看不初始化数据库或联网。
106
+
84
107
  ## Python
85
108
 
86
109
  公开请求模型与调用入口位于 quant_cli.api,与 CLI 使用同一应用服务。
@@ -30,7 +30,7 @@ pq config show
30
30
 
31
31
  家庭 LAN 可配置 `http://192.168.8.142:18026/market/api/v1`;公网 IP 临时入口为 `http://82.157.167.33/market/api/v1`。公网 HTTP 会明文传输 Token,只适合已明确接受风险的临时接入;长期公网访问使用可信 HTTPS 或 SSH/WireGuard 加密链路。直接使用 `https://82.157.167.33` 与现有域名证书不匹配。
32
32
 
33
- 配置保存在当前系统用户的 `~/.powerquant/config.json`,与工作目录无关,不自动加载 `.env`。这是本地明文配置:POSIX 新目录权限 700、文件权限 600;Windows 依赖用户目录 ACL,不声称加密存储。不要提交或分享该文件。
33
+ 配置保存在当前系统用户的 `~/.powerquant/config.yml`,与工作目录无关,不自动加载 `.env`。这是本地明文配置:POSIX 新目录权限 700、文件权限 600;Windows 依赖用户目录 ACL,不声称加密存储。不要提交或分享该文件。
34
34
 
35
35
  每项配置按环境变量 > 用户文件 > 默认值解析。默认地址为 `http://localhost:8002/api/v1`,默认 Token 为空。环境变量只影响当前终端及其启动的子进程,不改文件;显式空 Token 环境变量会覆盖已保存密钥。
36
36
 
@@ -56,10 +56,32 @@ cd powerquant-examples/selection
56
56
  pq data prepare --config prepare.json
57
57
  ```
58
58
 
59
- 按实际覆盖调整 prepare.json 的股票和日期,将返回 manifest_path 写入 compute.json、select.json;按示例 README 执行 compute、select 和 backtest。不同使用目的的快照须分别通过完整性检查。
59
+ 按实际覆盖调整 prepare.json 的股票和日期,将返回的 data.manifest_path 写入 compute.json、select.json;按示例 README 执行 compute、select 和 backtest。不同使用目的的快照须分别通过完整性检查。
60
60
 
61
61
  密钥到期或撤销后在线准备会失败,已下载快照仍可离线使用。行情密钥不用于定义发布;发布定义另使用 PQ_QUANT_URL/PQ_QUANT_TOKEN。默认本地目录为 ~/.powerquant。
62
62
 
63
+ ## Agent 使用
64
+
65
+ 命令结果统一输出 JSON `{status,data}`;错误以 JSON 写入 stderr,保留业务错误码、消息和 request_id,并返回非零退出码。
66
+
67
+ ```sh
68
+ pq --version
69
+ pq skill list
70
+ pq skill show pq-bootstrap
71
+ pq skill check
72
+ pq init
73
+ ```
74
+
75
+ `pq init` 先返回安装计划。使用返回的 `data.expected_plan` 执行 `pq init --confirm --expected-plan <expected_plan>`,默认安装到 Codex 的 `~/.agents/skills` 和 Claude Code 的 `~/.claude/skills`。可用 `--agent codex|claude|both` 选择客户端,或用 `--skills-dir` 指定项目目录。Hint 仅写入显式提供的 `--hint-file`,保留受管块外的内容。
76
+
77
+ 没有 Token 也可以初始化;需要连接行情时,按 bootstrap Skill 申请权限并通过 `pq config token` 安全录入。行情运维通过 PQData API/MCP 提交任务。
78
+
79
+ `pq upgrade` 先预览,再用 `--confirm --expected-plan <expected_plan>` 启动后台升级;通过 `pq agent upgrade-status <operation_id>` 查询结果。升级沿用 uv tool 或 pipx 安装渠道,并同步已登记的资源目录。`pq upgrade --skip-package` 仅同步资源。独立资源同步使用 `pq agent sync`,同样先预览再确认。
80
+
81
+ ## 依赖生命周期
82
+
83
+ ApplicationContainer 接收 ApplicationSettings,按需组装明确的因子、回测、研究应用 Service,CLI 从 ctx.obj 获取。Service 依赖由构造函数显式传入;不维护通用 Repository 缓存、不查询全局容器、不在缺少上下文时静默创建容器。MarketClient 按需创建并由调用方 async with 关闭,本地 Repository 使用短事务。配置、帮助和资源查看不初始化数据库或联网。
84
+
63
85
  ## Python
64
86
 
65
87
  公开请求模型与调用入口位于 quant_cli.api,与 CLI 使用同一应用服务。
@@ -30,6 +30,7 @@ from pqdata.schema.reference_schema import (
30
30
  TradingRuleResponse,
31
31
  )
32
32
  from pqdata.schema.reliability_schema import DatasetHealthResult
33
+ from pqdata.schema.snapshot_schema import PREPARATION_DATASETS, DatasetSnapshot, SnapshotQuery
33
34
 
34
35
 
35
36
  class MarketClient:
@@ -101,12 +102,50 @@ class MarketClient:
101
102
  await response.aclose()
102
103
  await asyncio.sleep(delay)
103
104
  if not response.is_success:
104
- raise MarketAPIError(response.status_code, response.headers.get("x-request-id"))
105
+ code: str | int | None = None
106
+ message: str | None = None
107
+ request_id = response.headers.get("x-request-id")
108
+ if "application/json" in response.headers.get("content-type", ""):
109
+ try:
110
+ error = response.json()
111
+ except ValueError:
112
+ error = None
113
+ if isinstance(error, dict):
114
+ candidate = error.get("error_code", error.get("code"))
115
+ if isinstance(candidate, (str, int)) and not isinstance(candidate, bool):
116
+ code = candidate
117
+ candidate = error.get("message")
118
+ if isinstance(candidate, str) and 0 < len(candidate) <= 512:
119
+ message = candidate
120
+ candidate = error.get("request_id")
121
+ if isinstance(candidate, str) and len(candidate) <= 128:
122
+ request_id = request_id or candidate
123
+ raise MarketAPIError(response.status_code, request_id, code=code, message=message)
105
124
  try:
106
125
  return TypeAdapter(response_type).validate_json(response.content)
107
126
  except ValidationError as error:
108
127
  raise MarketProtocolError("Invalid market response") from error
109
128
 
129
+ async def resolve_snapshot(
130
+ self,
131
+ datasets: list[str],
132
+ *,
133
+ instrument_ids: list[str] | None = None,
134
+ start: date | None = None,
135
+ end: date | None = None,
136
+ ) -> DatasetSnapshot:
137
+ query = SnapshotQuery(
138
+ datasets=datasets, instrument_ids=instrument_ids or [], start=start, end=end
139
+ )
140
+ return await self._request(
141
+ "POST", "snapshots/resolve", DatasetSnapshot, body=query.model_dump(mode="json")
142
+ )
143
+
144
+ async def inspect_snapshot(self, snapshot_id: str) -> DatasetSnapshot:
145
+ return await self._request(
146
+ "GET", f"snapshots/{quote(snapshot_id, safe='')}", DatasetSnapshot
147
+ )
148
+
110
149
  async def get_instrument(self, instrument_id: str) -> InstrumentResponse:
111
150
  return await self._request(
112
151
  "GET",
@@ -115,6 +154,9 @@ class MarketClient:
115
154
  )
116
155
 
117
156
  async def get_history_facts(self, query: HistoryFactsQuery) -> HistoryFacts:
157
+ if query.revision is None:
158
+ snapshot = await self.resolve_snapshot(PREPARATION_DATASETS)
159
+ query = query.model_copy(update={"revision": snapshot.snapshot_id})
118
160
  result = await self._request(
119
161
  "POST", "history/facts", HistoryFacts, body=query.model_dump(mode="json")
120
162
  )
@@ -170,8 +212,11 @@ class MarketClient:
170
212
  frequency: str,
171
213
  start: datetime,
172
214
  end: datetime,
215
+ *,
216
+ revision: str,
173
217
  ) -> DatasetHealthResult:
174
218
  query = DataHealthQuery(
219
+ revision=revision,
175
220
  instrument_id=instrument_id,
176
221
  frequency=TypeAdapter(BarFrequency).validate_python(frequency),
177
222
  start=start,
@@ -187,8 +232,11 @@ class MarketClient:
187
232
  frequency: str,
188
233
  start: datetime,
189
234
  end: datetime,
235
+ *,
236
+ revision: str,
190
237
  ) -> DatasetHealthResult:
191
238
  query = DataHealthQuery(
239
+ revision=revision,
192
240
  instrument_id=instrument_id,
193
241
  frequency=TypeAdapter(BarFrequency).validate_python(frequency),
194
242
  start=start,
@@ -206,8 +254,12 @@ class MarketClient:
206
254
  instrument_id: str,
207
255
  start: datetime,
208
256
  end: datetime,
257
+ *,
258
+ revision: str,
209
259
  ) -> DatasetHealthResult:
210
- query = DataHealthQuery(instrument_id=instrument_id, start=start, end=end)
260
+ query = DataHealthQuery(
261
+ revision=revision, instrument_id=instrument_id, start=start, end=end
262
+ )
211
263
  return await self._request(
212
264
  "POST",
213
265
  "verify/corporate-actions",
@@ -215,23 +267,13 @@ class MarketClient:
215
267
  body=query.model_dump(mode="json"),
216
268
  )
217
269
 
218
- async def snapshot(self, start: date, end: date) -> dict[str, str]:
219
- return await self._request(
220
- "GET",
221
- "revisions",
222
- dict[str, str],
223
- params={
224
- "start": start.isoformat(),
225
- "end": end.isoformat(),
226
- },
227
- )
228
-
229
270
  async def search_instruments(
230
271
  self,
231
272
  keyword: str | None = None,
232
273
  instrument_type: str | None = None,
233
274
  exchange: str | None = None,
234
275
  limit: int = 100,
276
+ revision: str | None = None,
235
277
  ) -> list[InstrumentResponse]:
236
278
  params = {
237
279
  key: value
@@ -243,6 +285,8 @@ class MarketClient:
243
285
  }.items()
244
286
  if value is not None
245
287
  }
288
+ if revision is not None:
289
+ params["revision"] = revision
246
290
  return await self._request("GET", "instruments", list[InstrumentResponse], params=params)
247
291
 
248
292
  async def list_instruments_on(
@@ -337,6 +381,9 @@ class MarketClient:
337
381
 
338
382
  async def query_bars(self, query: BarQuery) -> BarPage:
339
383
  """读取一页数据;错误内容不混入行情结果。"""
384
+ if query.revision is None:
385
+ snapshot = await self.resolve_snapshot(["bar"])
386
+ query = query.model_copy(update={"revision": snapshot.snapshot_id})
340
387
  page = await self._request(
341
388
  "POST", "bars/query", BarPage, body=query.model_dump(mode="json")
342
389
  )
@@ -359,6 +406,9 @@ class MarketClient:
359
406
 
360
407
  async def describe_bars(self, query: BarQuery) -> BarContent:
361
408
  """只传输范围摘要;服务端仍需扫描数据,不能视为常数成本的查询。"""
409
+ if query.revision is None:
410
+ snapshot = await self.resolve_snapshot(["bar"])
411
+ query = query.model_copy(update={"revision": snapshot.snapshot_id})
362
412
  if query.cursor is not None:
363
413
  raise ValueError("Content queries must start at the first page")
364
414
  result = await self._request(
@@ -4,10 +4,14 @@
4
4
  class MarketAPIError(Exception):
5
5
  """服务拒绝请求;保留状态码和可追踪的请求 ID,不暴露凭据。"""
6
6
 
7
- def __init__(self, status_code: int, request_id: str | None = None) -> None:
7
+ def __init__(self, status_code: int, request_id: str | None = None,
8
+ *, code: str | int | None = None, message: str | None = None) -> None:
8
9
  self.status_code = status_code
9
10
  self.request_id = request_id
10
- super().__init__(f"Market request failed (HTTP {status_code}, request_id={request_id})")
11
+ self.code = code if code is not None else f"HTTP_{status_code}"
12
+ self.message = message or f"行情请求失败(HTTP {status_code})"
13
+ super().__init__(self.message)
14
+
11
15
 
12
16
 
13
17
  class MarketProtocolError(Exception):
@@ -47,6 +47,7 @@ class PITWindowQuery(BaseModel):
47
47
 
48
48
 
49
49
  class DataHealthQuery(BaseModel):
50
+ revision: str
50
51
  instrument_id: str
51
52
  frequency: BarFrequency = "1d"
52
53
  start: AwareDatetime
@@ -0,0 +1,50 @@
1
+ """固定的数据集版本组合;内容身份和覆盖凭证独立表达。"""
2
+
3
+ from datetime import date
4
+
5
+ from pydantic import BaseModel, ConfigDict, Field, model_validator
6
+
7
+ PREPARATION_DATASETS = [
8
+ "bar",
9
+ "instrument",
10
+ "trading_calendar",
11
+ "trading_rule",
12
+ "instrument_daily_fact",
13
+ "adjustment_factor",
14
+ "corporate_action",
15
+ ]
16
+
17
+
18
+ class SnapshotQuery(BaseModel):
19
+ model_config = ConfigDict(extra="forbid")
20
+ datasets: list[str] = Field(min_length=1, max_length=9)
21
+ instrument_ids: list[str] = Field(default_factory=list, max_length=10000)
22
+ start: date | None = None
23
+ end: date | None = None
24
+
25
+ @model_validator(mode="after")
26
+ def scoped(self) -> "SnapshotQuery":
27
+ if (self.start is None) != (self.end is None):
28
+ raise ValueError("start 和 end 必须同时提供")
29
+ if self.start is not None and self.end is not None:
30
+ if not self.instrument_ids or not 0 <= (self.end - self.start).days <= 3660:
31
+ raise ValueError("范围解析需要标的及不超过十年的有效日期区间")
32
+ if not {"instrument", "trading_calendar"}.issubset(self.datasets):
33
+ raise ValueError("范围解析需要标的和交易日历数据集")
34
+ elif self.instrument_ids:
35
+ raise ValueError("标的范围需要日期区间")
36
+ return self
37
+
38
+
39
+ class DatasetVersionInfo(BaseModel):
40
+ rules_version: int = Field(ge=1)
41
+ contract_version: int = Field(ge=1)
42
+ version_id: str
43
+ root_hash: str
44
+ coverage: dict
45
+
46
+
47
+ class DatasetSnapshot(BaseModel):
48
+ snapshot_id: str
49
+ root_hash: str
50
+ datasets: dict[str, DatasetVersionInfo]
@@ -43,8 +43,10 @@ async def run(day: date, output: Path, minimum_amount: Decimal, top: int) -> dic
43
43
  if observed_at <= end:
44
44
  raise ValueError("只支持已结束的历史交易日")
45
45
  async with build_market_query() as client:
46
- revision = (await client.snapshot(day, day))["canonical"]
47
- catalog = await client.search_instruments(limit=10000)
46
+ revision = (
47
+ await client.resolve_snapshot(["bar", "instrument", "trading_calendar"])
48
+ ).snapshot_id
49
+ catalog = await client.search_instruments(limit=10000, revision=revision)
48
50
  if len(catalog) >= 10000:
49
51
  raise ValueError("标的目录可能截断,拒绝冒充全市场")
50
52
  stocks = [i for i in catalog if i.instrument_type == "stock"]
@@ -72,8 +74,6 @@ async def run(day: date, output: Path, minimum_amount: Decimal, top: int) -> dic
72
74
  raise ValueError("同一证券出现重复日线")
73
75
  bars[bar.instrument_id] = bar
74
76
  print(f"已读取 {min(offset + 1000, len(ids))}/{len(ids)} 只候选", flush=True)
75
- if (await client.snapshot(day, day))["canonical"] != revision:
76
- raise ValueError("读取期间数据修订变化,请重新运行")
77
77
  if not bars:
78
78
  raise ValueError("当日无日线数据")
79
79
  reasons = dict.fromkeys(unknown_listing, "unknown_listing_date")
@@ -1,12 +1,12 @@
1
1
  [project]
2
2
  name = "powerquant-cli"
3
- version = "0.2.7"
3
+ version = "0.2.10"
4
4
  description = "Power Quant local research CLI"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
7
7
  license = "LicenseRef-PowerQuant-Proprietary AND MIT"
8
8
  license-files = ["LICENSE", "licenses/LICENSE.vnpy"]
9
- dependencies = ["pydantic>=2.5,<3", "polars>=1.36,<2", "numpy>=2,<3", "scipy>=1.17,<2", "pandas>=3,<4", "tzdata>=2026.3", "typer>=0.27.2", "httpx>=0.28,<1", "duckdb>=1.4,<2", "filelock>=3.20,<4"]
9
+ dependencies = ["pydantic>=2.5,<3", "polars>=1.36,<2", "numpy>=2,<3", "scipy>=1.17,<2", "pandas>=3,<4", "tzdata>=2026.3", "typer>=0.27.2", "httpx>=0.28,<1", "duckdb>=1.4,<2", "filelock>=3.20,<4", "pyyaml>=6,<7"]
10
10
 
11
11
  [project.urls]
12
12
  Repository = "https://github.com/Kepler452Byte/power-quant"
@@ -19,7 +19,7 @@ build-backend = "hatchling.build"
19
19
  packages = ["src/quant_cli"]
20
20
 
21
21
  [dependency-groups]
22
- dev = ["powerquant-core==0.2.6", "powerquant-market==0.2.6", "pytest>=8", "pytest-asyncio>=0.24", "ruff>=0.6", "pyright>=1.1.380"]
22
+ dev = ["powerquant-core==0.2.6", "powerquant-market==0.3.0", "pytest>=8", "pytest-asyncio>=0.24", "ruff>=0.6", "pyright>=1.1.380"]
23
23
  [tool.ruff]
24
24
  line-length = 100
25
25
  target-version = "py312"
@@ -0,0 +1,70 @@
1
+ """Agent 资源命令:发现随包内容、预览安装与同步。"""
2
+
3
+ from pathlib import Path
4
+ from typing import Annotated
5
+
6
+ import typer
7
+
8
+ from quant_cli.app.agent_resources.schema.agent_resource_schema import AgentTarget
9
+ from quant_cli.app.cli_dependency import container
10
+ from quant_cli.common.command_error_handler import CommandGroup
11
+ from quant_cli.common.command_help import Command
12
+ from quant_cli.common.utils.cli_utils import cli_errors, output
13
+
14
+ app = typer.Typer(cls=CommandGroup, no_args_is_help=True, help="安装和同步受管 Agent 资源")
15
+ skill_app = typer.Typer(cls=CommandGroup, no_args_is_help=True, help="查看并校验随包 Skill")
16
+
17
+
18
+ @skill_app.command("list", cls=Command)
19
+ @cli_errors
20
+ def list_skills(ctx: typer.Context) -> None:
21
+ output(container(ctx).agent_resource_service.list_skills())
22
+
23
+
24
+ @skill_app.command("show", cls=Command)
25
+ @cli_errors
26
+ def show_skill(ctx: typer.Context, name: str, file: str = typer.Option("SKILL.md")) -> None:
27
+ output(container(ctx).agent_resource_service.show(name, file))
28
+
29
+
30
+ @skill_app.command("check", cls=Command)
31
+ @cli_errors
32
+ def check_skills(ctx: typer.Context) -> None:
33
+ output(container(ctx).agent_resource_service.check())
34
+
35
+
36
+ @app.command("install", cls=Command)
37
+ @cli_errors
38
+ def install_agent(
39
+ ctx: typer.Context,
40
+ agent: Annotated[AgentTarget, typer.Option()] = AgentTarget.BOTH,
41
+ skills_dir: Annotated[
42
+ Path | None, typer.Option(help="自定义 Skill 目录,替代客户端默认目录")
43
+ ] = None,
44
+ hint_file: Annotated[list[Path] | None, typer.Option(help="显式 Hint 目标,可重复")] = None,
45
+ confirm: bool = typer.Option(False),
46
+ expected_plan: str | None = typer.Option(None),
47
+ ) -> None:
48
+ result = container(ctx).bootstrap_service.install(
49
+ agent.value, skills_dir, tuple(hint_file or ()), confirm, expected_plan
50
+ )
51
+ output(result, status="applied" if confirm else "planned")
52
+
53
+
54
+ @app.command("sync", cls=Command)
55
+ @cli_errors
56
+ def sync_agent(
57
+ ctx: typer.Context,
58
+ confirm: bool = typer.Option(False),
59
+ expected_plan: str | None = typer.Option(None),
60
+ ) -> None:
61
+ output(
62
+ container(ctx).agent_resource_service.sync(confirm, expected_plan),
63
+ status="applied" if confirm else "planned",
64
+ )
65
+
66
+
67
+ def register_agent_commands(root: typer.Typer) -> typer.Typer:
68
+ root.add_typer(skill_app, name="skill")
69
+ root.add_typer(app, name="agent")
70
+ return app
@@ -0,0 +1,14 @@
1
+ """Public resource alignment port used by system upgrade."""
2
+
3
+ from pathlib import Path
4
+ from typing import Protocol
5
+
6
+
7
+ class IAgentResourceSync(Protocol):
8
+ def sync(
9
+ self,
10
+ confirm: bool = False,
11
+ expected_plan: str | None = None,
12
+ skills_dirs: tuple[Path, ...] = (),
13
+ hint_files: tuple[Path, ...] = (),
14
+ ) -> dict[str, object]: ...
@@ -0,0 +1,57 @@
1
+ """Read packaged assets and persist explicitly addressed files."""
2
+
3
+ from contextlib import AbstractContextManager
4
+ from importlib import metadata, resources
5
+ from importlib.resources.abc import Traversable
6
+ from pathlib import Path
7
+
8
+ from quant_cli.common.filesystem import atomic_write, read_bytes, safe_path, write_lock
9
+
10
+
11
+ class AgentResourceRepository:
12
+ def __init__(
13
+ self, distribution: str, command: str, state_root: Path, package: str = "quant_cli"
14
+ ):
15
+ self.distribution = distribution
16
+ self.command = command
17
+ self.state_root = state_root.expanduser().absolute()
18
+ self.package = package
19
+ self.registry_path = self.state_root / "resources.json"
20
+
21
+ def assets(self) -> dict[str, bytes]:
22
+ root = resources.files(self.package).joinpath("resources", "skills")
23
+ assets: dict[str, bytes] = {}
24
+
25
+ def visit(node: Traversable, prefix: str) -> None:
26
+ for child in sorted(node.iterdir(), key=lambda item: item.name):
27
+ relative = prefix + child.name
28
+ if child.is_dir():
29
+ visit(child, relative + "/")
30
+ else:
31
+ assets[relative] = child.read_bytes()
32
+
33
+ if root.is_dir():
34
+ visit(root, "")
35
+ return assets
36
+
37
+ def version(self) -> str:
38
+ return metadata.version(self.distribution)
39
+
40
+ def hint(self) -> bytes:
41
+ path = resources.files(self.package).joinpath("resources", "agent_hint.md")
42
+ return path.read_bytes() if path.is_file() else b""
43
+
44
+ def resolve(self, path: Path) -> Path:
45
+ return safe_path(path)
46
+
47
+ def read(self, path: Path) -> bytes | None:
48
+ return read_bytes(path)
49
+
50
+ def write(self, path: Path, content: bytes) -> None:
51
+ atomic_write(path, content)
52
+
53
+ def remove(self, path: Path) -> None:
54
+ safe_path(path).unlink(missing_ok=True)
55
+
56
+ def lock(self, targets: list[Path]) -> AbstractContextManager[None]:
57
+ return write_lock(self.state_root, targets)
@@ -0,0 +1,89 @@
1
+ """Resource ownership records and explicit synchronization plans."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from dataclasses import asdict, dataclass
7
+ from enum import StrEnum
8
+ from pathlib import Path
9
+
10
+ from quant_cli.common.hashing import digest
11
+ from quant_cli.common.operation_error import OperationError
12
+
13
+
14
+ class AgentTarget(StrEnum):
15
+ CODEX = "codex"
16
+ CLAUDE = "claude"
17
+ BOTH = "both"
18
+
19
+
20
+ @dataclass(frozen=True)
21
+ class OwnedFile:
22
+ path: str
23
+ kind: str
24
+
25
+
26
+ @dataclass
27
+ class Registry:
28
+ distribution: str
29
+ skills: list[str]
30
+ hints: list[str]
31
+ files: list[OwnedFile]
32
+
33
+ @classmethod
34
+ def load(cls, raw: bytes, distribution: str) -> Registry:
35
+ try:
36
+ data = json.loads(raw)
37
+ if (
38
+ not isinstance(data, dict)
39
+ or set(data) != {"distribution", "skills", "hints", "files"}
40
+ or data.get("distribution") != distribution
41
+ ):
42
+ raise ValueError("identity")
43
+ skills, hints, files = data["skills"], data["hints"], data["files"]
44
+ if not all(isinstance(items, list) for items in (skills, hints, files)):
45
+ raise ValueError("lists")
46
+ if not all(isinstance(item, str) for item in [*skills, *hints]):
47
+ raise ValueError("paths")
48
+ if not all(Path(item).is_absolute() for item in [*skills, *hints]):
49
+ raise ValueError("absolute paths")
50
+ owned: list[OwnedFile] = []
51
+ for item in files:
52
+ if (
53
+ not isinstance(item, dict)
54
+ or set(item) != {"path", "kind"}
55
+ or not all(isinstance(item.get(key), str) for key in ("path", "kind"))
56
+ ):
57
+ raise ValueError("files")
58
+ if item["kind"] not in {"skill", "hint"}:
59
+ raise ValueError("kind")
60
+ owned.append(OwnedFile(item["path"], item["kind"]))
61
+ if len({item.path for item in owned}) != len(owned):
62
+ raise ValueError("duplicate paths")
63
+ return cls(distribution, skills, hints, owned)
64
+ except (ValueError, KeyError, TypeError) as exc:
65
+ raise OperationError(
66
+ "Resource registry is invalid; preserve it and repair explicitly",
67
+ "invalid-registry",
68
+ ) from exc
69
+
70
+ def encode(self) -> bytes:
71
+ return (
72
+ json.dumps(asdict(self), sort_keys=True, ensure_ascii=False, indent=2) + "\n"
73
+ ).encode()
74
+
75
+
76
+ @dataclass(frozen=True)
77
+ class Change:
78
+ path: Path
79
+ before: str
80
+ content: bytes | None
81
+ action: str
82
+
83
+ def describe(self) -> dict[str, str]:
84
+ return {
85
+ "path": str(self.path),
86
+ "action": self.action,
87
+ "expected_hash": self.before,
88
+ "new_hash": digest(self.content),
89
+ }