quantnodes 3.0.0__tar.gz → 3.0.1__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 (437) hide show
  1. {quantnodes-3.0.0 → quantnodes-3.0.1}/PKG-INFO +1 -1
  2. quantnodes-3.0.1/QuantNodes/agent/skills_quant/logic-mining/SKILL.md +50 -0
  3. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/logic_driven_pipeline.py +11 -0
  4. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/logic_mining/__init__.py +9 -0
  5. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/logic_mining/generator.py +96 -11
  6. quantnodes-3.0.1/QuantNodes/research/quant_alpha/logic_mining/metrics.py +134 -0
  7. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/logic_mining/models.py +6 -0
  8. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/logic_mining/parser.py +85 -20
  9. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/logic_mining/pipelines.py +112 -6
  10. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/logic_mining/sources.py +31 -6
  11. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/workflow/alpha_logics.py +127 -13
  12. {quantnodes-3.0.0 → quantnodes-3.0.1}/pyproject.toml +1 -1
  13. {quantnodes-3.0.0 → quantnodes-3.0.1}/quantnodes.egg-info/PKG-INFO +1 -1
  14. {quantnodes-3.0.0 → quantnodes-3.0.1}/quantnodes.egg-info/SOURCES.txt +2 -0
  15. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/__init__.py +0 -0
  16. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/__main__.py +0 -0
  17. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/__init__.py +0 -0
  18. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/agents/__init__.py +0 -0
  19. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/agents/definition.py +0 -0
  20. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/agents/manager.py +0 -0
  21. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/config/__init__.py +0 -0
  22. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/config/executor.py +0 -0
  23. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/config/loader.py +0 -0
  24. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/config/templates/bollinger_bands.yaml +0 -0
  25. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/config/templates/dual_ma.yaml +0 -0
  26. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/config/templates/empty.yaml +0 -0
  27. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/config/templates/mean_reversion.yaml +0 -0
  28. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/config/templates/mean_reversion_zscore.yaml +0 -0
  29. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/config/templates/momentum.yaml +0 -0
  30. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/config/templates/momentum_breakout.yaml +0 -0
  31. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/config/templates/rsi_strategy.yaml +0 -0
  32. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/config/templates/volume_price.yaml +0 -0
  33. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/config/types.py +0 -0
  34. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/config_mapper.py +0 -0
  35. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/core/__init__.py +0 -0
  36. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/core/dream.py +0 -0
  37. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/core/quant_dream.py +0 -0
  38. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/cron_jobs.py +0 -0
  39. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/nanobot_bridge.py +0 -0
  40. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/permission/__init__.py +0 -0
  41. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/permission/defaults.py +0 -0
  42. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/permission/evaluate.py +0 -0
  43. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/permission/models.py +0 -0
  44. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/permission/service.py +0 -0
  45. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/providers/__init__.py +0 -0
  46. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/providers/base.py +0 -0
  47. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/providers/quantnodes.py +0 -0
  48. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/providers/rate_limiter.py +0 -0
  49. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/providers/registry.py +0 -0
  50. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/skills/__init__.py +0 -0
  51. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/skills/base.py +0 -0
  52. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/skills/bridge.py +0 -0
  53. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/skills/factor/__init__.py +0 -0
  54. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/skills/factor/correlation.py +0 -0
  55. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/skills/factor/group_backtest.py +0 -0
  56. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/skills/factor/ic_analysis.py +0 -0
  57. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/skills/loader.py +0 -0
  58. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/skills/registry.py +0 -0
  59. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/skills/strategy/__init__.py +0 -0
  60. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/skills/strategy/bollinger.py +0 -0
  61. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/skills/strategy/dual_ma.py +0 -0
  62. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/skills/strategy/momentum.py +0 -0
  63. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/skills/strategy/rsi_reversal.py +0 -0
  64. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/skills_quant/__init__.py +0 -0
  65. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/skills_quant/backtest-analyze/SKILL.md +0 -0
  66. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/skills_quant/config-driven/SKILL.md +0 -0
  67. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/skills_quant/factor-research/SKILL.md +0 -0
  68. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/skills_quant/quant-dream/SKILL.md +0 -0
  69. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/skills_quant/risk-management/SKILL.md +0 -0
  70. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/skills_quant/strategy-design/SKILL.md +0 -0
  71. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/templates/__init__.py +0 -0
  72. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/__init__.py +0 -0
  73. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/_workspace.py +0 -0
  74. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/alpha_backtest.py +0 -0
  75. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/alpha_evaluate.py +0 -0
  76. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/backtest.py +0 -0
  77. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/base.py +0 -0
  78. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/code_search.py +0 -0
  79. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/config_backtest.py +0 -0
  80. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/context.py +0 -0
  81. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/dream_skill.py +0 -0
  82. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/echo.py +0 -0
  83. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/factor.py +0 -0
  84. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/file_ops.py +0 -0
  85. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/git_ops.py +0 -0
  86. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/operator_lookup.py +0 -0
  87. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/output_truncation.py +0 -0
  88. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/path_check.py +0 -0
  89. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/pipeline.py +0 -0
  90. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/registry.py +0 -0
  91. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/sandbox.py +0 -0
  92. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/shell_safety.py +0 -0
  93. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/strategy.py +0 -0
  94. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/task.py +0 -0
  95. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/web_fetch.py +0 -0
  96. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/web_search.py +0 -0
  97. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/tools/wiki.py +0 -0
  98. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/utils/__init__.py +0 -0
  99. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/utils/helpers.py +0 -0
  100. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/utils/prompt_templates.py +0 -0
  101. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/workflows/__init__.py +0 -0
  102. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/workflows/implementations/__init__.py +0 -0
  103. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/workflows/implementations/alpha_gpt.py +0 -0
  104. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/workflows/implementations/mcts.py +0 -0
  105. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/workflows/parsers.py +0 -0
  106. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/workflows/registry.py +0 -0
  107. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/workflows/step_agent.py +0 -0
  108. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/agent/workflows/tool.py +0 -0
  109. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/ai/__init__.py +0 -0
  110. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/ai/llm/__init__.py +0 -0
  111. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/ai/llm/base.py +0 -0
  112. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/ai/llm/decorators.py +0 -0
  113. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/ai/llm/gateway.py +0 -0
  114. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/ai/llm/null.py +0 -0
  115. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/ai/llm/openai.py +0 -0
  116. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/ai/optimizer.py +0 -0
  117. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/ai/prompts/__init__.py +0 -0
  118. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/ai/sandbox.py +0 -0
  119. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/ai/sandbox_pandas_bridge.py +0 -0
  120. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/ai/strategy_gen.py +0 -0
  121. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/backtest/__init__.py +0 -0
  122. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/backtest/backtest_node.py +0 -0
  123. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/backtest/broker_node.py +0 -0
  124. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/backtest/config_runner.py +0 -0
  125. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/backtest/config_strategy.py +0 -0
  126. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/backtest/risk_node.py +0 -0
  127. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/backtest/strategy_node.py +0 -0
  128. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/cache_node/__init__.py +0 -0
  129. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/cache_node/base.py +0 -0
  130. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/cache_node/cache_store.py +0 -0
  131. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/cache_node/metadata.py +0 -0
  132. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/cli/__init__.py +0 -0
  133. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/cli/_helpers.py +0 -0
  134. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/cli/command.py +0 -0
  135. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/cli/commands/__init__.py +0 -0
  136. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/cli/commands/agent.py +0 -0
  137. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/cli/commands/alpha.py +0 -0
  138. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/cli/commands/chat.py +0 -0
  139. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/cli/commands/evolve.py +0 -0
  140. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/cli/commands/factor.py +0 -0
  141. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/cli/commands/init.py +0 -0
  142. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/cli/commands/run.py +0 -0
  143. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/cli/commands/serve.py +0 -0
  144. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/cli/commands/version.py +0 -0
  145. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/cli/enhanced.py +0 -0
  146. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/conf_node/__init__.py +0 -0
  147. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/conf_node/base.py +0 -0
  148. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/conf_node/env_config.py +0 -0
  149. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/conf_node/ini_config.py +0 -0
  150. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/conf_node/json_config.py +0 -0
  151. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/conf_node/yaml_config.py +0 -0
  152. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/constants.py +0 -0
  153. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/__init__.py +0 -0
  154. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/_lookback_helpers.py +0 -0
  155. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/ast_parser.py +0 -0
  156. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/base.py +0 -0
  157. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/cache_manager.py +0 -0
  158. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/cache_utils.py +0 -0
  159. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/cond_builder.py +0 -0
  160. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/config.py +0 -0
  161. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/constants.py +0 -0
  162. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/control.py +0 -0
  163. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/data_preprocessing.py +0 -0
  164. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/data_source.py +0 -0
  165. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/events.py +0 -0
  166. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/evolution/__init__.py +0 -0
  167. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/evolution/loop.py +0 -0
  168. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/evolution/operators.py +0 -0
  169. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/evolution/settings.py +0 -0
  170. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/expression.py +0 -0
  171. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/feedback/__init__.py +0 -0
  172. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/feedback/channels.py +0 -0
  173. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/feedback/collector.py +0 -0
  174. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/feedback/dataclass.py +0 -0
  175. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/feedback/llm_judge.py +0 -0
  176. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/knowledge/__init__.py +0 -0
  177. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/knowledge/knowledge_base.py +0 -0
  178. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/knowledge/lineage_compress.py +0 -0
  179. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/knowledge/lineage_expand.py +0 -0
  180. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/knowledge/metrics/__init__.py +0 -0
  181. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/knowledge/metrics/evaluator.py +0 -0
  182. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/knowledge/metrics/metrics.py +0 -0
  183. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/knowledge/rag_prompt.py +0 -0
  184. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/knowledge/retriever.py +0 -0
  185. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/lambda_node.py +0 -0
  186. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/monitoring/__init__.py +0 -0
  187. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/monitoring/collector.py +0 -0
  188. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/monitoring/dashboard.py +0 -0
  189. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/node.py +0 -0
  190. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/pandas_utils.py +0 -0
  191. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/parallel/__init__.py +0 -0
  192. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/parallel/worker.py +0 -0
  193. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/parallel/worker_process.py +0 -0
  194. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/path_utils.py +0 -0
  195. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/pipeline.py +0 -0
  196. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/plugin.py +0 -0
  197. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/quality_gate/__init__.py +0 -0
  198. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/quality_gate/complexity.py +0 -0
  199. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/quality_gate/consistency.py +0 -0
  200. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/quality_gate/node.py +0 -0
  201. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/quality_gate/redundancy.py +0 -0
  202. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/quality_gate/settings.py +0 -0
  203. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/quality_gate/zoo.py +0 -0
  204. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/serializable.py +0 -0
  205. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/serialization.py +0 -0
  206. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/tools.py +0 -0
  207. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/trajectory/__init__.py +0 -0
  208. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/trajectory/entry.py +0 -0
  209. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/trajectory/lineage.py +0 -0
  210. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/trajectory/pool.py +0 -0
  211. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/trajectory/selector.py +0 -0
  212. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/visualization/__init__.py +0 -0
  213. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/visualization/builder.py +0 -0
  214. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/visualization/gate_breakdown.py +0 -0
  215. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/visualization/lineage_dag.py +0 -0
  216. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/visualization/metric_distribution.py +0 -0
  217. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/core/visualization/report.py +0 -0
  218. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/database_node/__init__.py +0 -0
  219. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/database_node/base.py +0 -0
  220. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/database_node/clickhouse_node.py +0 -0
  221. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/database_node/csv_node.py +0 -0
  222. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/database_node/duckdb_node.py +0 -0
  223. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/database_node/factory.py +0 -0
  224. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/database_node/mysql_node.py +0 -0
  225. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/database_node/parquet_node.py +0 -0
  226. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/database_node/sqlite_node.py +0 -0
  227. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/factor_node/__init__.py +0 -0
  228. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/factor_node/factor.py +0 -0
  229. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/factor_node/factor_db.py +0 -0
  230. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/factor_node/factor_functions/__init__.py +0 -0
  231. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/factor_node/factor_functions/_helpers.py +0 -0
  232. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/factor_node/factor_functions/_helpers_debug.py +0 -0
  233. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/factor_node/factor_functions/composite_ops.py +0 -0
  234. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/factor_node/factor_functions/math_ops.py +0 -0
  235. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/factor_node/factor_functions/section_ops.py +0 -0
  236. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/factor_node/factor_functions/talib_ops.py +0 -0
  237. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/factor_node/factor_functions/time_ops.py +0 -0
  238. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/factor_node/factor_operation.py +0 -0
  239. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/factor_node/factor_table.py +0 -0
  240. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/factor_node/quant_nodes_object.py +0 -0
  241. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/mcp_server/__init__.py +0 -0
  242. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/mcp_server/__main__.py +0 -0
  243. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/mcp_server/server.py +0 -0
  244. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/methods/__init__.py +0 -0
  245. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/methods/pipeline.py +0 -0
  246. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/methods/sandbox.py +0 -0
  247. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/monitor/__init__.py +0 -0
  248. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/monitor/agent_tools/__init__.py +0 -0
  249. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/monitor/agent_tools/monitor_tool.py +0 -0
  250. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/monitor/agent_tools/schedule_tool.py +0 -0
  251. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/monitor/agent_tools/version_tool.py +0 -0
  252. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/monitor/monitor/__init__.py +0 -0
  253. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/monitor/monitor/alerter.py +0 -0
  254. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/monitor/monitor/collector.py +0 -0
  255. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/monitor/monitor/dashboard.py +0 -0
  256. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/monitor/monitor/drift.py +0 -0
  257. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/monitor/scheduler/__init__.py +0 -0
  258. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/monitor/scheduler/runner.py +0 -0
  259. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/monitor/scheduler/scheduler.py +0 -0
  260. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/monitor/storage/__init__.py +0 -0
  261. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/monitor/storage/models.py +0 -0
  262. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/monitor/storage/repository.py +0 -0
  263. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/monitor/version/__init__.py +0 -0
  264. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/monitor/version/diff.py +0 -0
  265. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/monitor/version/version_manager.py +0 -0
  266. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/operator_node/__init__.py +0 -0
  267. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/operator_node/base.py +0 -0
  268. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/operator_node/query_node.py +0 -0
  269. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/operator_node/sql_builder.py +0 -0
  270. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/operator_node/sql_utils.py +0 -0
  271. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/operator_node/transform.py +0 -0
  272. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/operators/__init__.py +0 -0
  273. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/operators/_engine.py +0 -0
  274. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/operators/composite.py +0 -0
  275. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/operators/composite_dag.py +0 -0
  276. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/operators/composite_dag_ops.py +0 -0
  277. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/operators/composite_dag_pandas_ops.py +0 -0
  278. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/operators/custom.py +0 -0
  279. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/operators/facade.py +0 -0
  280. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/operators/math.py +0 -0
  281. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/operators/proxy.py +0 -0
  282. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/operators/registry.py +0 -0
  283. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/operators/section.py +0 -0
  284. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/operators/talib.py +0 -0
  285. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/operators/templates.py +0 -0
  286. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/operators/time_series.py +0 -0
  287. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/prompts/__init__.py +0 -0
  288. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/prompts/backtest/__init__.py +0 -0
  289. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/prompts/backtest/factor_based.py +0 -0
  290. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/prompts/backtest/standard.py +0 -0
  291. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/prompts/factor/__init__.py +0 -0
  292. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/prompts/factor/correlation.py +0 -0
  293. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/prompts/factor/group_backtest.py +0 -0
  294. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/prompts/factor/ic_analysis.py +0 -0
  295. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/prompts/strategy/__init__.py +0 -0
  296. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/prompts/strategy/market_neutral.py +0 -0
  297. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/prompts/strategy/mean_reversion.py +0 -0
  298. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/prompts/strategy/momentum.py +0 -0
  299. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/prompts/strategy/pairs_trading.py +0 -0
  300. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/prompts/strategy/trend_following.py +0 -0
  301. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/README.md +0 -0
  302. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/__init__.py +0 -0
  303. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/_legacy_3c/__init__.py +0 -0
  304. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/_legacy_3c/auto_researcher.py +0 -0
  305. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/_legacy_3c/factor_evaluator.py +0 -0
  306. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/_legacy_3c/factor_miner.py +0 -0
  307. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/_legacy_3c/mcts_search.py +0 -0
  308. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/__init__.py +0 -0
  309. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/config.py +0 -0
  310. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/config_builder.py +0 -0
  311. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/e2e/data_prep.py +0 -0
  312. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/e2e/run_evolution_e2e.py +0 -0
  313. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/evolution_adapter.py +0 -0
  314. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/feedback_wrapper.py +0 -0
  315. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/ifind_db/__init__.py +0 -0
  316. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/ifind_db/fetcher.py +0 -0
  317. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/ifind_db/ifind_database.py +0 -0
  318. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/nodes/__init__.py +0 -0
  319. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/nodes/_base.py +0 -0
  320. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/nodes/adjust_date_node.py +0 -0
  321. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/nodes/configs.py +0 -0
  322. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/nodes/factor_neutralize_node.py +0 -0
  323. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/nodes/factor_preprocess_node.py +0 -0
  324. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/nodes/factor_score_node.py +0 -0
  325. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/nodes/factor_test_report_node.py +0 -0
  326. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/nodes/group_analyzer_node.py +0 -0
  327. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/nodes/ic_analyzer_node.py +0 -0
  328. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/nodes/load_data_node.py +0 -0
  329. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/nodes/long_short_node.py +0 -0
  330. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/nodes/neutralizers.py +0 -0
  331. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/nodes/preprocess_strategies.py +0 -0
  332. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/nodes/risk_correlation_node.py +0 -0
  333. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/nodes/sample_pool_filter_node.py +0 -0
  334. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/nodes/tradability_filter_node.py +0 -0
  335. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/pipeline_runner.py +0 -0
  336. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/pipeline_spec.py +0 -0
  337. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/utils/__init__.py +0 -0
  338. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/utils/constants.py +0 -0
  339. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/utils/data_loader.py +0 -0
  340. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/utils/date_utils.py +0 -0
  341. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/utils/file_loaders.py +0 -0
  342. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/utils/labels.py +0 -0
  343. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/utils/metrics_extractor.py +0 -0
  344. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/utils/performance_metrics.py +0 -0
  345. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/factor_test/utils/safe_load.py +0 -0
  346. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/CHANGELOG.md +0 -0
  347. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/README.md +0 -0
  348. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/__init__.py +0 -0
  349. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/adapters/__init__.py +0 -0
  350. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/adapters/calculator.py +0 -0
  351. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/adapters/expression.py +0 -0
  352. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/alpha101_design/__init__.py +0 -0
  353. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/alpha101_design/few_shot_examples.py +0 -0
  354. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/alpha101_design/philosophy.py +0 -0
  355. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/alpha158_design/__init__.py +0 -0
  356. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/alpha158_design/few_shot_examples.py +0 -0
  357. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/alpha158_design/philosophy.py +0 -0
  358. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/evaluation/__init__.py +0 -0
  359. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/evaluation/baselines/__init__.py +0 -0
  360. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/evaluation/baselines/g1_handcrafted.py +0 -0
  361. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/evaluation/baselines/g2_llm_only.py +0 -0
  362. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/evaluation/baselines/g3_alpha_gpt.py +0 -0
  363. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/evaluation/clickhouse_data_loader.py +0 -0
  364. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/evaluation/contracts.py +0 -0
  365. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/evaluation/evaluators/__init__.py +0 -0
  366. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/evaluation/evaluators/polars_evaluator.py +0 -0
  367. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/evaluation/mock_data_loader.py +0 -0
  368. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/evaluation/runner.py +0 -0
  369. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/llm/__init__.py +0 -0
  370. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/llm/parser.py +0 -0
  371. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/logic_mining/compiler.py +0 -0
  372. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/mcts/__init__.py +0 -0
  373. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/mcts/cache.py +0 -0
  374. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/mcts/extension_ops.py +0 -0
  375. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/mcts/feedback.py +0 -0
  376. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/mcts/op_prior.py +0 -0
  377. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/mcts/search.py +0 -0
  378. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/mcts/tree.py +0 -0
  379. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/operator_vocab/__init__.py +0 -0
  380. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/operator_vocab/config.py +0 -0
  381. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/operator_vocab/metadata.py +0 -0
  382. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/operator_vocab/vocabulary.py +0 -0
  383. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/pipeline.py +0 -0
  384. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/types/__init__.py +0 -0
  385. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/types/constants.py +0 -0
  386. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/types/state.py +0 -0
  387. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/workflow/__init__.py +0 -0
  388. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/workflow/alpha_gpt.py +0 -0
  389. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/quant_alpha/workflow/state.py +0 -0
  390. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/report_reproducer.py +0 -0
  391. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/research/wiki.py +0 -0
  392. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/symbolic/__init__.py +0 -0
  393. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/symbolic/compiler.py +0 -0
  394. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/symbolic/dialect.py +0 -0
  395. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/symbolic/executor.py +0 -0
  396. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/symbolic/expression.py +0 -0
  397. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/symbolic/functions.py +0 -0
  398. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/symbolic/optimizer.py +0 -0
  399. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/ui_node/__init__.py +0 -0
  400. {quantnodes-3.0.0 → quantnodes-3.0.1}/QuantNodes/ui_node/base.py +0 -0
  401. {quantnodes-3.0.0 → quantnodes-3.0.1}/README.md +0 -0
  402. {quantnodes-3.0.0 → quantnodes-3.0.1}/quantnodes.egg-info/dependency_links.txt +0 -0
  403. {quantnodes-3.0.0 → quantnodes-3.0.1}/quantnodes.egg-info/entry_points.txt +0 -0
  404. {quantnodes-3.0.0 → quantnodes-3.0.1}/quantnodes.egg-info/requires.txt +0 -0
  405. {quantnodes-3.0.0 → quantnodes-3.0.1}/quantnodes.egg-info/top_level.txt +0 -0
  406. {quantnodes-3.0.0 → quantnodes-3.0.1}/setup.cfg +0 -0
  407. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_ai.py +0 -0
  408. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_backtest_node.py +0 -0
  409. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_base_node.py +0 -0
  410. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_cli_enhanced.py +0 -0
  411. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_composite_dag.py +0 -0
  412. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_composite_dag_engine.py +0 -0
  413. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_composite_dag_ops.py +0 -0
  414. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_composite_dag_pandas_engine.py +0 -0
  415. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_composite_dag_pandas_ops.py +0 -0
  416. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_config_node.py +0 -0
  417. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_control.py +0 -0
  418. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_database_node.py +0 -0
  419. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_database_node_factory.py +0 -0
  420. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_example_strategies.py +0 -0
  421. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_expression.py +0 -0
  422. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_factor_functions.py +0 -0
  423. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_full_market_performance.py +0 -0
  424. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_group_analyzer_bool.py +0 -0
  425. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_mcp_server.py +0 -0
  426. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_operator_node.py +0 -0
  427. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_operators_engine_registry_zoo.py +0 -0
  428. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_pipeline.py +0 -0
  429. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_pipeline_plugin.py +0 -0
  430. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_profile_single.py +0 -0
  431. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_sandbox_allowed_imports.py +0 -0
  432. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_sandbox_pandas_bridge.py +0 -0
  433. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_serialization.py +0 -0
  434. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_settings_page.py +0 -0
  435. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_symbolic.py +0 -0
  436. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_talib.py +0 -0
  437. {quantnodes-3.0.0 → quantnodes-3.0.1}/tests/test_ui_node.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quantnodes
3
- Version: 3.0.0
3
+ Version: 3.0.1
4
4
  Summary: AI-native quantitative research framework with symbolic computation and SQL pushdown
5
5
  Author-email: sn0wfree <snowfreedom0815@gmail.com>
6
6
  License: MIT
@@ -0,0 +1,50 @@
1
+ ---
2
+ name: logic-mining
3
+ description: 市场逻辑驱动的自动化因子挖掘 — Logic Mining + Γ 约束内层生成 + Wiki 沉淀。
4
+ ---
5
+
6
+ # Logic Mining (v3.0.1)
7
+
8
+ 驱动 QuantNodes Logic Mining 端到端工作流:选取 source → 3-stage LLM 抽取逻辑 → 编译 Γ 约束 → 内层 Alpha-GPT 受约束生成因子 → 外层重构 → 写入 Wiki。
9
+
10
+ ## 工作流
11
+
12
+ 1. **选 source 与定逻辑种子** — 调用 `sources.list_available_sources` 列数据源 (`alpha101` / `alpha158` / `alpha191`),`sources.get_formulas_from_source(lib, max_count=N, only_volume_price=True)` 加载前 N 条公式
13
+ 2. **3-stage 抽取逻辑** — 对每条公式:
14
+ - 调用 `LogicMiningPipeline.run(formula, source_lib=lib)` 走 3 个 sub-agent (structure / semantics / abstraction)
15
+ - 返回 `LogicAbstractionResult` 含 `structured_logic` (`WikiLogicStructured`)
16
+ 3. **编译 Γ 约束** — 调用 `logic_mining.compile_to_constraint(logic.structured, source_logic=name)` 生成 `CompiledConstraint`
17
+ 4. **注入 Alpha-GPT** — 在 `AlphaGptConfig.gamma = gamma` 透传;下游 `_step_formula_translator` 拒绝任何不符合 Γ 的公式
18
+ 5. **内层循环** — 调用 `AlphaGptWorkflow(config=...).run()`,产出 inner_results 与 per-logic `LogicPerformanceEvidence`
19
+ 6. **外层重构** — 调用 `MarketLogicGenerator.generate(library, current_logic, history, evidence, round_idx)` 与 `MarketLogicRefinementDirection.refine(...)` 进入下一轮 Algorithm 2 编排
20
+ 7. **沉淀 Wiki** — 调用 `wiki_write` 写入 `Logic/` 页面,附 Γ + evidence
21
+
22
+ ## 工具集
23
+
24
+ | 工具 | 用途 |
25
+ |------|------|
26
+ | `logic_mine` | `mine_logic_from_formula(formula, source_lib, llm_client)` 走 3-stage |
27
+ | `logic_compile` | `compile_to_constraint(logic, source_logic)` 生成 Γ |
28
+ | `logic_refine` | `MarketLogicRefinementDirection.refine(current_logic, history, evidence)` |
29
+ | `logic_validate` | `gamma.validate(formula_str)` 校验公式是否过 Γ |
30
+ | `logic_library_build` | `build_initial_logic_library(source_libs, llm_client, max_per_lib)` |
31
+ | `wiki_write` | 写入 Wiki Logic 页面 |
32
+
33
+ ## 验收标准
34
+
35
+ - 初始逻辑库 ≥ 5 条 (从 alpha101 / alpha158 抽取)
36
+ - 每条逻辑最终 γ.validate(formula) 在示例上通过
37
+ - per-logic evidence 包含 `n_factors_explored` / `best_ir` / `best_ic`
38
+ - IR 上升 → 窗口收窄 20% (Phase 3 P0-3 修复)
39
+ - best_ic != best_ir (Phase 3 P0-2 修复)
40
+ - alpha191 source 不再静默 (Phase 3 P0-1 修复)
41
+ - silent fallback 通过 `pipeline.metrics` / `result.diagnostics` 暴露 (Phase 2)
42
+ - 可选 `strict=StrictConfig(...)` 把失败升级为异常
43
+
44
+ ## 反模式
45
+
46
+ - 不要直接调用 inner AlphaGptWorkflow 而跳过 3-stage logic 抽取(失去 Logic Mining 意义)
47
+ - 不要忽略 `result.parse_error` / `result.diagnostics` 字段(silent fallback 信号)
48
+ - 不要用 `best_ic` 字段当 IR 读 (v3.0.0 时期旧 docstring 是错的, P0-2 已修)
49
+ - 不要在 IR 上升时反转 sign(这是 IR 下降的响应)
50
+ - 不要修改 alpha191 数据源逻辑,它是 OHLCV-only 守卫
@@ -41,6 +41,8 @@ import polars as pl
41
41
  from QuantNodes.research.quant_alpha.logic_mining import (
42
42
  WikiLogicStructured,
43
43
  LogicPerformanceEvidence,
44
+ PipelineMetrics,
45
+ StrictConfig,
44
46
  )
45
47
  from QuantNodes.research.quant_alpha.pipeline import (
46
48
  AlphaPipeline,
@@ -124,6 +126,10 @@ class LogicDrivenPipelineConfig:
124
126
  alphalogics_initial_sources: Tuple[str, ...] = ("alpha101", "alpha158")
125
127
  alphalogics_initial_max_per_lib: int = 3
126
128
 
129
+ # v3.0.1 (Phase 2): silent fallback 可观测性
130
+ metrics: Optional[PipelineMetrics] = None
131
+ strict: Optional[StrictConfig] = None
132
+
127
133
  # 终止条件
128
134
  timeout_seconds: int = 3600
129
135
 
@@ -172,6 +178,8 @@ class LogicDrivenPipeline:
172
178
  ):
173
179
  self.config = config
174
180
  self.llm_client = llm_client
181
+ self.metrics: PipelineMetrics = config.metrics or PipelineMetrics()
182
+ self.strict: StrictConfig = config.strict or StrictConfig()
175
183
 
176
184
  def run(self, data: pl.DataFrame) -> LogicDrivenPipelineResult:
177
185
  """运行 Pipeline
@@ -273,6 +281,9 @@ class LogicDrivenPipeline:
273
281
  initial_logic_sources=self.config.alphalogics_initial_sources,
274
282
  initial_logic_max_per_lib=self.config.alphalogics_initial_max_per_lib,
275
283
  min_ir_threshold=self.config.min_ir_threshold,
284
+ # v3.0.1 (Phase 2): silent fallback 可观测性透传
285
+ metrics=self.metrics,
286
+ strict=self.strict,
276
287
  )
277
288
  workflow = AlphaLogicsWorkflow(config=config, llm_client=self.llm_client)
278
289
  return workflow.run()
@@ -44,6 +44,11 @@ from QuantNodes.research.quant_alpha.logic_mining.generator import (
44
44
  MarketLogicRefinementDirection,
45
45
  generate_logic_name,
46
46
  )
47
+ from QuantNodes.research.quant_alpha.logic_mining.metrics import (
48
+ PipelineMetrics,
49
+ StrictConfig,
50
+ LogicMiningStrictError,
51
+ )
47
52
 
48
53
  __all__ = [
49
54
  # Models
@@ -71,4 +76,8 @@ __all__ = [
71
76
  "MarketLogicGenerator",
72
77
  "MarketLogicRefinementDirection",
73
78
  "generate_logic_name",
79
+ # Metrics (v3.0.1 Phase 2)
80
+ "PipelineMetrics",
81
+ "StrictConfig",
82
+ "LogicMiningStrictError",
74
83
  ]
@@ -35,6 +35,11 @@ from QuantNodes.research.quant_alpha.logic_mining.models import (
35
35
  LogicPerformanceEvidence,
36
36
  WikiLogicStructured,
37
37
  )
38
+ from QuantNodes.research.quant_alpha.logic_mining.metrics import (
39
+ LogicMiningStrictError,
40
+ PipelineMetrics,
41
+ StrictConfig,
42
+ )
38
43
  from QuantNodes.research.quant_alpha.logic_mining.parser import (
39
44
  parse_json_response,
40
45
  )
@@ -58,8 +63,18 @@ __all__ = [
58
63
  ]
59
64
 
60
65
 
61
- def _call_llm(llm_client: Any, agent_id: str, prompt: str, default_response: str) -> str:
62
- """调用 LLM,无客户端或失败时返回 mock"""
66
+ def _call_llm(
67
+ llm_client: Any,
68
+ agent_id: str,
69
+ prompt: str,
70
+ default_response: str,
71
+ metrics: Optional[PipelineMetrics] = None,
72
+ strict: Optional[StrictConfig] = None,
73
+ ) -> str:
74
+ """调用 LLM,无客户端或失败时返回 mock
75
+
76
+ v3.0.1 (Phase 2): metrics 接入与 strict 模式开关
77
+ """
63
78
  if llm_client is None:
64
79
  return default_response
65
80
  try:
@@ -68,6 +83,15 @@ def _call_llm(llm_client: Any, agent_id: str, prompt: str, default_response: str
68
83
  return llm_client(prompt)
69
84
  except Exception as e:
70
85
  logger.warning("LLM call failed for %s: %s, falling back to mock", agent_id, e)
86
+ if metrics is not None:
87
+ metrics.record_call_failure(agent_id)
88
+ if strict is not None and strict.call:
89
+ raise LogicMiningStrictError(
90
+ f"LLM call failed for {agent_id}: {e}",
91
+ kind="call",
92
+ agent_id=agent_id,
93
+ original_error=repr(e),
94
+ ) from e
71
95
  return default_response
72
96
 
73
97
 
@@ -171,9 +195,19 @@ class MarketLogicGenerator:
171
195
  """MarketLogicGeneratorAgent
172
196
 
173
197
  在初始轮基于 ℋ_init 发散生成;后续轮基于 ℋ_lib + 历史证据做有方向的生成/重构。
198
+
199
+ v3.0.1 (Phase 2): metrics/strict 入参透传给 _call_llm 与 _structured_from_dict
174
200
  """
175
201
  llm_client: Any = None
176
202
  base_name: str = "alpha_logic"
203
+ metrics: Optional[PipelineMetrics] = None
204
+ strict: Optional[StrictConfig] = None
205
+
206
+ def __post_init__(self) -> None:
207
+ if self.metrics is None:
208
+ self.metrics = PipelineMetrics()
209
+ if self.strict is None:
210
+ self.strict = StrictConfig()
177
211
 
178
212
  def generate(
179
213
  self,
@@ -206,11 +240,22 @@ class MarketLogicGenerator:
206
240
  # 调用 LLM
207
241
  prompt = _build_generator_prompt(library, current_logic, history, evidence, round_idx)
208
242
  raw = _call_llm(
209
- self.llm_client, "market-logic-generator", prompt, mock_response
243
+ self.llm_client, "market-logic-generator", prompt, mock_response,
244
+ metrics=self.metrics, strict=self.strict,
210
245
  )
211
246
  result = parse_json_response(raw)
212
247
  if not result.ok:
213
248
  logger.warning("MarketLogicGenerator parse failed: %s, using mock data", result.error)
249
+ self.metrics.record_parse_failure("market-logic-generator", result.layer_reached)
250
+ if self.strict.parse:
251
+ raise LogicMiningStrictError(
252
+ f"MarketLogicGenerator parse failed at layer {result.layer_reached}: "
253
+ f"{result.error}",
254
+ kind="parse",
255
+ agent_id="market-logic-generator",
256
+ layer=result.layer_reached,
257
+ last_error=result.last_error,
258
+ )
214
259
  data = json.loads(mock_response)
215
260
  else:
216
261
  data = result.data
@@ -221,7 +266,15 @@ class MarketLogicGenerator:
221
266
  structured = _structured_from_dict(data)
222
267
  except Exception as e:
223
268
  logger.warning("Failed to build WikiLogicStructured: %s", e)
269
+ self.metrics.record_structured_failure("market-logic-generator")
224
270
  structured = None
271
+ if self.strict.structured:
272
+ raise LogicMiningStrictError(
273
+ f"WikiLogicStructured build failed: {e}",
274
+ kind="structured",
275
+ agent_id="market-logic-generator",
276
+ original_error=repr(e),
277
+ ) from e
225
278
 
226
279
  parent = current_logic.name if current_logic else None
227
280
  WikiLogic = _get_wiki_logic_class()
@@ -246,13 +299,18 @@ class MarketLogicGenerator:
246
299
  evidence: List[LogicPerformanceEvidence],
247
300
  round_idx: int,
248
301
  ) -> str:
249
- """Mock 响应:基于历史证据趋势生成"""
302
+ """Mock 响应:基于历史证据趋势生成
303
+
304
+ v3.0.1 (Phase 3, P0-3):
305
+ - IR 上升: 窗口收窄 20% (在已有 parameter_ranges 上动), sign 保留
306
+ - IR 下降: 反转 sign
307
+ """
250
308
  # 基于当前逻辑变体
251
309
  if current_logic and current_logic.structured:
252
310
  base_predicates = [p.to_dict() for p in current_logic.structured.predicates]
253
311
  beh = current_logic.structured.behavior.to_dict()
254
312
  whitelist = current_logic.structured.operator_whitelist or ["rank"]
255
- param_ranges = None
313
+ param_ranges: Dict[str, List[float]] = {}
256
314
  if current_logic.structured.parameter_ranges:
257
315
  param_ranges = {
258
316
  k: list(v)
@@ -268,12 +326,18 @@ class MarketLogicGenerator:
268
326
 
269
327
  # 根据 evidence 调整
270
328
  if evidence and len(evidence) >= 2:
271
- # IR 提升则保持方向,否则反转
272
- if evidence[-1].best_ir > evidence[-2].best_ir:
273
- # 继续优化
274
- pass
329
+ cur, prev = evidence[-1], evidence[-2]
330
+ if cur.best_ir > prev.best_ir and cur.n_factors_explored > 0:
331
+ # IR 提升 + 有可分析因子 → 窗口收窄 20%, 保留 sign
332
+ for op_key in list(param_ranges.keys()):
333
+ lo, hi = param_ranges[op_key]
334
+ if hi - lo > 1e-9:
335
+ span = hi - lo
336
+ new_lo = lo + span * 0.2
337
+ new_hi = hi - span * 0.2
338
+ param_ranges[op_key] = [new_lo, new_hi]
275
339
  else:
276
- # 反转方向
340
+ # IR 未升 → 反转 sign
277
341
  sign = -sign if sign else 1
278
342
 
279
343
  return json.dumps({
@@ -291,8 +355,18 @@ class MarketLogicRefinementDirection:
291
355
  """MarketLogicRefinementDirectionAgent
292
356
 
293
357
  综合所有该逻辑名下因子的回测表现,识别"逻辑过宽/过窄/与市场结构错配"的部分。
358
+
359
+ v3.0.1 (Phase 2): metrics/strict 入参透传
294
360
  """
295
361
  llm_client: Any = None
362
+ metrics: Optional[PipelineMetrics] = None
363
+ strict: Optional[StrictConfig] = None
364
+
365
+ def __post_init__(self) -> None:
366
+ if self.metrics is None:
367
+ self.metrics = PipelineMetrics()
368
+ if self.strict is None:
369
+ self.strict = StrictConfig()
296
370
 
297
371
  def refine(
298
372
  self,
@@ -323,11 +397,22 @@ class MarketLogicRefinementDirection:
323
397
  # 调用 LLM
324
398
  prompt = _build_refiner_prompt(current_logic, history, evidence)
325
399
  raw = _call_llm(
326
- self.llm_client, "market-logic-refinement", prompt, mock_response
400
+ self.llm_client, "market-logic-refinement", prompt, mock_response,
401
+ metrics=self.metrics, strict=self.strict,
327
402
  )
328
403
  result = parse_json_response(raw)
329
404
  if not result.ok:
330
405
  logger.warning("Refinement parse failed: %s, using mock", result.error)
406
+ self.metrics.record_parse_failure("market-logic-refinement", result.layer_reached)
407
+ if self.strict.parse:
408
+ raise LogicMiningStrictError(
409
+ f"MarketLogicRefinement parse failed at layer {result.layer_reached}: "
410
+ f"{result.error}",
411
+ kind="parse",
412
+ agent_id="market-logic-refinement",
413
+ layer=result.layer_reached,
414
+ last_error=result.last_error,
415
+ )
331
416
  data = json.loads(mock_response)
332
417
  else:
333
418
  data = result.data
@@ -0,0 +1,134 @@
1
+ # coding=utf-8
2
+ """
3
+ metrics.py - Logic Mining 可观测性 & 严格模式
4
+
5
+ Phase 2 (v3.0.1) 引入。为 silent-fallback 提供可观测指标,
6
+ 允许外部代码在 strict=True 时升级异常。
7
+
8
+ 设计要点:
9
+ - 6 类计数 (call_failures / parse_failures / parse_layer_reached /
10
+ structured_failures / wiki_failures / inner_loop_failures)
11
+ - PipelineMetrics 实例默认字段为空, 跨阶段共享
12
+ - StrictConfig: 三挡开关 (call/parse/structured) 默认全 False
13
+ - LogicMiningStrictError: strict=True 下静默升级为异常
14
+
15
+ Usage::
16
+
17
+ from QuantNodes.research.quant_alpha.logic_mining.metrics import (
18
+ PipelineMetrics, StrictConfig, LogicMiningStrictError,
19
+ )
20
+
21
+ metrics = PipelineMetrics()
22
+ strict = StrictConfig(parse=True)
23
+
24
+ pipeline = LogicMiningPipeline(llm_client=client, metrics=metrics, strict=strict)
25
+ ...
26
+ print(metrics.to_dict())
27
+ """
28
+
29
+ from __future__ import annotations
30
+
31
+ from collections import defaultdict
32
+ from dataclasses import dataclass, field
33
+ from typing import Any, DefaultDict, Dict, Optional
34
+
35
+
36
+ @dataclass
37
+ class StrictConfig:
38
+ """严格模式配置: 控制哪些 silent fallback 升级为异常
39
+
40
+ Attributes:
41
+ call: True 时 LLM 调用失败抛 LogicMiningStrictError
42
+ parse: True 时 JSON parse 失败抛 LogicMiningStrictError
43
+ structured: True 时 WikiLogicStructured 构建失败抛 LogicMiningStrictError
44
+ """
45
+ call: bool = False
46
+ parse: bool = False
47
+ structured: bool = False
48
+
49
+ @classmethod
50
+ def all_off(cls) -> "StrictConfig":
51
+ return cls()
52
+
53
+
54
+ @dataclass
55
+ class PipelineMetrics:
56
+ """Logic Mining 可观测性指标
57
+
58
+ 全部为弱默认, 调用方无须设置即可使用。线程不安全 (单线程 pipeline)
59
+ """
60
+ call_failures: DefaultDict[str, int] = field(default_factory=lambda: defaultdict(int))
61
+ parse_failures: DefaultDict[str, int] = field(default_factory=lambda: defaultdict(int))
62
+ parse_layer_reached: DefaultDict[str, int] = field(default_factory=lambda: defaultdict(int))
63
+ structured_failures: DefaultDict[str, int] = field(default_factory=lambda: defaultdict(int))
64
+ wiki_failures: int = 0
65
+ inner_loop_failures: int = 0
66
+
67
+ def record_call_failure(self, agent_id: str) -> None:
68
+ """记录 LLM 调用失败"""
69
+ self.call_failures[agent_id] += 1
70
+
71
+ def record_parse_failure(self, agent_id: str, layer_reached: int) -> None:
72
+ """记录 JSON 解析失败 + 最远触达层"""
73
+ self.parse_failures[agent_id] += 1
74
+ cur = self.parse_layer_reached[agent_id]
75
+ if layer_reached > cur:
76
+ self.parse_layer_reached[agent_id] = layer_reached
77
+
78
+ def record_structured_failure(self, agent_id: str) -> None:
79
+ """记录 WikiLogicStructured 数据解析失败"""
80
+ self.structured_failures[agent_id] += 1
81
+
82
+ def record_wiki_failure(self) -> None:
83
+ """记录 Wiki persistence 失败"""
84
+ self.wiki_failures += 1
85
+
86
+ def record_inner_loop_failure(self) -> None:
87
+ """记录内层 AlphaGptWorkflow 失败"""
88
+ self.inner_loop_failures += 1
89
+
90
+ def to_dict(self) -> Dict[str, Any]:
91
+ """导出为可序列化字典"""
92
+ return {
93
+ "call_failures": dict(self.call_failures),
94
+ "parse_failures": dict(self.parse_failures),
95
+ "parse_layer_reached": dict(self.parse_layer_reached),
96
+ "structured_failures": dict(self.structured_failures),
97
+ "wiki_failures": self.wiki_failures,
98
+ "inner_loop_failures": self.inner_loop_failures,
99
+ }
100
+
101
+ def total_failures(self) -> int:
102
+ """总失败计数"""
103
+ return (
104
+ sum(self.call_failures.values())
105
+ + sum(self.parse_failures.values())
106
+ + sum(self.structured_failures.values())
107
+ + self.wiki_failures
108
+ + self.inner_loop_failures
109
+ )
110
+
111
+
112
+ class LogicMiningStrictError(RuntimeError):
113
+ """strict=True 模式下静默失败升级为异常
114
+
115
+ 异常 message 包含:
116
+ - kind: 'call' / 'parse' / 'structured' / 'wiki' / 'inner_loop'
117
+ - agent_id / layer / 等上下文
118
+ """
119
+
120
+ def __init__(self, message: str, *, kind: str, **context: Any) -> None:
121
+ super().__init__(message)
122
+ self.kind = kind
123
+ self.context: Dict[str, Any] = dict(context)
124
+
125
+ def __repr__(self) -> str:
126
+ ctx = ", ".join(f"{k}={v!r}" for k, v in self.context.items())
127
+ return f"LogicMiningStrictError({self.kind}, {ctx}): {self.args[0]}"
128
+
129
+
130
+ __all__ = [
131
+ "PipelineMetrics",
132
+ "StrictConfig",
133
+ "LogicMiningStrictError",
134
+ ]
@@ -234,12 +234,16 @@ class LogicAbstractionResult:
234
234
  structured_logic: MarketLogicAbstractionAgent 输出
235
235
  source_formula: 原始公式
236
236
  source_lib: 来源库 ("alpha101" / "alpha158" / "alpha191")
237
+ parse_error: v3.0.1 暴露三段式 parse 失败原因 (None=全成功)
238
+ parse_layer: v3.0.1 记录最远触达的 layer (1/2/3), 0=空
237
239
  """
238
240
  formula_structure: Dict[str, Any] = field(default_factory=dict)
239
241
  financial_semantics: Dict[str, Any] = field(default_factory=dict)
240
242
  structured_logic: Optional[WikiLogicStructured] = None
241
243
  source_formula: str = ""
242
244
  source_lib: str = ""
245
+ parse_error: Optional[str] = None
246
+ parse_layer: int = 0
243
247
 
244
248
  def to_dict(self) -> Dict[str, Any]:
245
249
  """转换为字典"""
@@ -249,4 +253,6 @@ class LogicAbstractionResult:
249
253
  "structured_logic": self.structured_logic.to_dict() if self.structured_logic else None,
250
254
  "source_formula": self.source_formula,
251
255
  "source_lib": self.source_lib,
256
+ "parse_error": self.parse_error,
257
+ "parse_layer": self.parse_layer,
252
258
  }
@@ -22,7 +22,7 @@ from __future__ import annotations
22
22
  import json
23
23
  import logging
24
24
  import re
25
- from dataclasses import dataclass
25
+ from dataclasses import dataclass, field
26
26
  from typing import Any, Dict, List, Optional, Tuple
27
27
 
28
28
  logger = logging.getLogger(__name__)
@@ -41,11 +41,24 @@ __all__ = [
41
41
 
42
42
  @dataclass
43
43
  class ParseResult:
44
- """JSON 解析结果"""
44
+ """JSON 解析结果 (v3.0.1: 新增 layer_reached / last_error / layer_errors)
45
+
46
+ Attributes:
47
+ ok: 是否成功解析
48
+ data: 成功时的 dict (其余情况为 None)
49
+ error: 失败原因 (聚合)
50
+ raw: 原始输入文本
51
+ layer_reached: 触达的最高层 (0=空/未尝试, 1=直接, 2=md fence, 3=brace)
52
+ last_error: 最近一次的 JSONDecodeError 文本
53
+ layer_errors: 各层的错误文本 (用于定位失败层)
54
+ """
45
55
  ok: bool
46
56
  data: Optional[Dict[str, Any]] = None
47
57
  error: Optional[str] = None
48
58
  raw: str = ""
59
+ layer_reached: int = 0
60
+ last_error: Optional[str] = None
61
+ layer_errors: Dict[int, str] = field(default_factory=dict)
49
62
 
50
63
 
51
64
  def parse_json_response(raw: str) -> ParseResult:
@@ -59,34 +72,61 @@ def parse_json_response(raw: str) -> ParseResult:
59
72
  raw: LLM 输出文本
60
73
 
61
74
  Returns:
62
- ParseResult
75
+ ParseResult — 失败时 layer_reached=0/1/2/3 标识最远触达层,
76
+ last_error 与 layer_errors 暴露每个被吞掉的 JSONDecodeError
63
77
  """
64
78
  if not raw:
65
- return ParseResult(ok=False, error="empty response", raw=raw)
79
+ return ParseResult(
80
+ ok=False, error="empty response", raw=raw,
81
+ layer_reached=0, last_error=None, layer_errors={},
82
+ )
66
83
 
67
84
  # 第 1 层: 直接 JSON
68
85
  try:
69
- return ParseResult(ok=True, data=json.loads(raw), raw=raw)
70
- except json.JSONDecodeError:
71
- pass
86
+ return ParseResult(
87
+ ok=True, data=json.loads(raw), raw=raw,
88
+ layer_reached=1, last_error=None, layer_errors={},
89
+ )
90
+ except json.JSONDecodeError as e:
91
+ first_err = str(e)
72
92
 
73
93
  # 第 2 层: 从 ```json ... ``` 中提取
74
94
  md_match = re.search(r"```(?:json)?\s*(\{.*?\})\s*```", raw, re.DOTALL)
95
+ layer_errors: Dict[int, str] = {1: first_err}
75
96
  if md_match:
76
97
  try:
77
- return ParseResult(ok=True, data=json.loads(md_match.group(1)), raw=raw)
78
- except json.JSONDecodeError:
79
- pass
98
+ return ParseResult(
99
+ ok=True, data=json.loads(md_match.group(1)), raw=raw,
100
+ layer_reached=2, last_error=None, layer_errors=layer_errors,
101
+ )
102
+ except json.JSONDecodeError as e:
103
+ layer_errors[2] = str(e)
104
+ last_err = str(e)
105
+ else:
106
+ last_err = first_err
80
107
 
81
108
  # 第 3 层: 找第一个 {...} 块
82
109
  brace_match = re.search(r"\{.*\}", raw, re.DOTALL)
83
110
  if brace_match:
84
111
  try:
85
- return ParseResult(ok=True, data=json.loads(brace_match.group(0)), raw=raw)
86
- except json.JSONDecodeError:
87
- pass
88
-
89
- return ParseResult(ok=False, error="Cannot parse JSON after 3 layers", raw=raw)
112
+ return ParseResult(
113
+ ok=True, data=json.loads(brace_match.group(0)), raw=raw,
114
+ layer_reached=3, last_error=None, layer_errors=layer_errors,
115
+ )
116
+ except json.JSONDecodeError as e:
117
+ layer_errors[3] = str(e)
118
+ last_err = str(e)
119
+
120
+ # 全部失败
121
+ max_layer = max(layer_errors.keys()) if layer_errors else 0
122
+ return ParseResult(
123
+ ok=False,
124
+ error=f"Cannot parse JSON after 3 layers (last layer={max_layer})",
125
+ raw=raw,
126
+ layer_reached=max_layer,
127
+ last_error=last_err,
128
+ layer_errors=layer_errors,
129
+ )
90
130
 
91
131
 
92
132
  def parse_formula_structure(raw: str) -> ParseResult:
@@ -106,11 +146,21 @@ def parse_formula_structure(raw: str) -> ParseResult:
106
146
 
107
147
  data = result.data
108
148
  if not isinstance(data, dict):
109
- return ParseResult(ok=False, error="data is not a dict", raw=raw)
149
+ return ParseResult(
150
+ ok=False, error="data is not a dict", raw=raw,
151
+ layer_reached=result.layer_reached,
152
+ last_error=result.last_error,
153
+ layer_errors=result.layer_errors,
154
+ )
110
155
 
111
156
  # 必填字段验证
112
157
  if "operations" not in data:
113
- return ParseResult(ok=False, error="missing 'operations' field", raw=raw)
158
+ return ParseResult(
159
+ ok=False, error="missing 'operations' field", raw=raw,
160
+ layer_reached=result.layer_reached,
161
+ last_error=result.last_error,
162
+ layer_errors=result.layer_errors,
163
+ )
114
164
 
115
165
  # 填充默认值
116
166
  validated = {
@@ -140,7 +190,12 @@ def parse_financial_semantics(raw: str) -> ParseResult:
140
190
 
141
191
  data = result.data
142
192
  if not isinstance(data, dict):
143
- return ParseResult(ok=False, error="data is not a dict", raw=raw)
193
+ return ParseResult(
194
+ ok=False, error="data is not a dict", raw=raw,
195
+ layer_reached=result.layer_reached,
196
+ last_error=result.last_error,
197
+ layer_errors=result.layer_errors,
198
+ )
144
199
 
145
200
  validated = {
146
201
  "price_role": data.get("price_role", "unknown"),
@@ -170,11 +225,21 @@ def parse_market_logic(raw: str) -> ParseResult:
170
225
 
171
226
  data = result.data
172
227
  if not isinstance(data, dict):
173
- return ParseResult(ok=False, error="data is not a dict", raw=raw)
228
+ return ParseResult(
229
+ ok=False, error="data is not a dict", raw=raw,
230
+ layer_reached=result.layer_reached,
231
+ last_error=result.last_error,
232
+ layer_errors=result.layer_errors,
233
+ )
174
234
 
175
235
  # 必填字段验证
176
236
  if "predicates" not in data or "behavior" not in data:
177
- return ParseResult(ok=False, error="missing 'predicates' or 'behavior'", raw=raw)
237
+ return ParseResult(
238
+ ok=False, error="missing 'predicates' or 'behavior'", raw=raw,
239
+ layer_reached=result.layer_reached,
240
+ last_error=result.last_error,
241
+ layer_errors=result.layer_errors,
242
+ )
178
243
 
179
244
  return ParseResult(ok=True, data=data, raw=raw)
180
245