quantnodes 3.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (399) hide show
  1. QuantNodes/__init__.py +15 -0
  2. QuantNodes/__main__.py +14 -0
  3. QuantNodes/agent/__init__.py +158 -0
  4. QuantNodes/agent/agents/__init__.py +13 -0
  5. QuantNodes/agent/agents/definition.py +180 -0
  6. QuantNodes/agent/agents/manager.py +73 -0
  7. QuantNodes/agent/config/__init__.py +34 -0
  8. QuantNodes/agent/config/executor.py +958 -0
  9. QuantNodes/agent/config/loader.py +427 -0
  10. QuantNodes/agent/config/templates/bollinger_bands.yaml +84 -0
  11. QuantNodes/agent/config/templates/dual_ma.yaml +72 -0
  12. QuantNodes/agent/config/templates/empty.yaml +56 -0
  13. QuantNodes/agent/config/templates/mean_reversion.yaml +47 -0
  14. QuantNodes/agent/config/templates/mean_reversion_zscore.yaml +90 -0
  15. QuantNodes/agent/config/templates/momentum.yaml +81 -0
  16. QuantNodes/agent/config/templates/momentum_breakout.yaml +84 -0
  17. QuantNodes/agent/config/templates/rsi_strategy.yaml +72 -0
  18. QuantNodes/agent/config/templates/volume_price.yaml +86 -0
  19. QuantNodes/agent/config/types.py +156 -0
  20. QuantNodes/agent/config_mapper.py +293 -0
  21. QuantNodes/agent/core/__init__.py +19 -0
  22. QuantNodes/agent/core/dream.py +47 -0
  23. QuantNodes/agent/core/quant_dream.py +274 -0
  24. QuantNodes/agent/cron_jobs.py +314 -0
  25. QuantNodes/agent/nanobot_bridge.py +242 -0
  26. QuantNodes/agent/permission/__init__.py +30 -0
  27. QuantNodes/agent/permission/defaults.py +36 -0
  28. QuantNodes/agent/permission/evaluate.py +41 -0
  29. QuantNodes/agent/permission/models.py +59 -0
  30. QuantNodes/agent/permission/service.py +133 -0
  31. QuantNodes/agent/providers/__init__.py +11 -0
  32. QuantNodes/agent/providers/base.py +102 -0
  33. QuantNodes/agent/providers/quantnodes.py +610 -0
  34. QuantNodes/agent/providers/rate_limiter.py +326 -0
  35. QuantNodes/agent/providers/registry.py +163 -0
  36. QuantNodes/agent/skills/__init__.py +20 -0
  37. QuantNodes/agent/skills/base.py +118 -0
  38. QuantNodes/agent/skills/bridge.py +73 -0
  39. QuantNodes/agent/skills/factor/__init__.py +14 -0
  40. QuantNodes/agent/skills/factor/correlation.py +99 -0
  41. QuantNodes/agent/skills/factor/group_backtest.py +114 -0
  42. QuantNodes/agent/skills/factor/ic_analysis.py +106 -0
  43. QuantNodes/agent/skills/loader.py +107 -0
  44. QuantNodes/agent/skills/registry.py +105 -0
  45. QuantNodes/agent/skills/strategy/__init__.py +16 -0
  46. QuantNodes/agent/skills/strategy/bollinger.py +86 -0
  47. QuantNodes/agent/skills/strategy/dual_ma.py +82 -0
  48. QuantNodes/agent/skills/strategy/momentum.py +74 -0
  49. QuantNodes/agent/skills/strategy/rsi_reversal.py +99 -0
  50. QuantNodes/agent/skills_quant/__init__.py +14 -0
  51. QuantNodes/agent/skills_quant/backtest-analyze/SKILL.md +42 -0
  52. QuantNodes/agent/skills_quant/config-driven/SKILL.md +72 -0
  53. QuantNodes/agent/skills_quant/factor-research/SKILL.md +40 -0
  54. QuantNodes/agent/skills_quant/quant-dream/SKILL.md +55 -0
  55. QuantNodes/agent/skills_quant/risk-management/SKILL.md +45 -0
  56. QuantNodes/agent/skills_quant/strategy-design/SKILL.md +43 -0
  57. QuantNodes/agent/templates/__init__.py +4 -0
  58. QuantNodes/agent/tools/__init__.py +173 -0
  59. QuantNodes/agent/tools/_workspace.py +51 -0
  60. QuantNodes/agent/tools/alpha_backtest.py +328 -0
  61. QuantNodes/agent/tools/alpha_evaluate.py +493 -0
  62. QuantNodes/agent/tools/backtest.py +226 -0
  63. QuantNodes/agent/tools/base.py +133 -0
  64. QuantNodes/agent/tools/code_search.py +207 -0
  65. QuantNodes/agent/tools/config_backtest.py +401 -0
  66. QuantNodes/agent/tools/context.py +97 -0
  67. QuantNodes/agent/tools/dream_skill.py +77 -0
  68. QuantNodes/agent/tools/echo.py +38 -0
  69. QuantNodes/agent/tools/factor.py +231 -0
  70. QuantNodes/agent/tools/file_ops.py +201 -0
  71. QuantNodes/agent/tools/git_ops.py +190 -0
  72. QuantNodes/agent/tools/operator_lookup.py +218 -0
  73. QuantNodes/agent/tools/output_truncation.py +77 -0
  74. QuantNodes/agent/tools/path_check.py +43 -0
  75. QuantNodes/agent/tools/pipeline.py +62 -0
  76. QuantNodes/agent/tools/registry.py +150 -0
  77. QuantNodes/agent/tools/sandbox.py +62 -0
  78. QuantNodes/agent/tools/shell_safety.py +63 -0
  79. QuantNodes/agent/tools/strategy.py +106 -0
  80. QuantNodes/agent/tools/task.py +171 -0
  81. QuantNodes/agent/tools/web_fetch.py +142 -0
  82. QuantNodes/agent/tools/web_search.py +114 -0
  83. QuantNodes/agent/tools/wiki.py +370 -0
  84. QuantNodes/agent/utils/__init__.py +11 -0
  85. QuantNodes/agent/utils/helpers.py +43 -0
  86. QuantNodes/agent/utils/prompt_templates.py +30 -0
  87. QuantNodes/agent/workflows/__init__.py +20 -0
  88. QuantNodes/agent/workflows/implementations/__init__.py +8 -0
  89. QuantNodes/agent/workflows/implementations/alpha_gpt.py +508 -0
  90. QuantNodes/agent/workflows/implementations/mcts.py +442 -0
  91. QuantNodes/agent/workflows/parsers.py +44 -0
  92. QuantNodes/agent/workflows/registry.py +119 -0
  93. QuantNodes/agent/workflows/step_agent.py +219 -0
  94. QuantNodes/agent/workflows/tool.py +198 -0
  95. QuantNodes/ai/__init__.py +93 -0
  96. QuantNodes/ai/llm/__init__.py +75 -0
  97. QuantNodes/ai/llm/base.py +233 -0
  98. QuantNodes/ai/llm/decorators.py +281 -0
  99. QuantNodes/ai/llm/gateway.py +571 -0
  100. QuantNodes/ai/llm/null.py +76 -0
  101. QuantNodes/ai/llm/openai.py +435 -0
  102. QuantNodes/ai/optimizer.py +405 -0
  103. QuantNodes/ai/prompts/__init__.py +229 -0
  104. QuantNodes/ai/sandbox.py +371 -0
  105. QuantNodes/ai/sandbox_pandas_bridge.py +150 -0
  106. QuantNodes/ai/strategy_gen.py +396 -0
  107. QuantNodes/backtest/__init__.py +64 -0
  108. QuantNodes/backtest/backtest_node.py +188 -0
  109. QuantNodes/backtest/broker_node.py +378 -0
  110. QuantNodes/backtest/config_runner.py +397 -0
  111. QuantNodes/backtest/config_strategy.py +64 -0
  112. QuantNodes/backtest/risk_node.py +360 -0
  113. QuantNodes/backtest/strategy_node.py +268 -0
  114. QuantNodes/cache_node/__init__.py +19 -0
  115. QuantNodes/cache_node/base.py +244 -0
  116. QuantNodes/cache_node/cache_store.py +99 -0
  117. QuantNodes/cache_node/metadata.py +100 -0
  118. QuantNodes/cli/__init__.py +109 -0
  119. QuantNodes/cli/_helpers.py +511 -0
  120. QuantNodes/cli/command.py +110 -0
  121. QuantNodes/cli/commands/__init__.py +69 -0
  122. QuantNodes/cli/commands/agent.py +158 -0
  123. QuantNodes/cli/commands/alpha.py +951 -0
  124. QuantNodes/cli/commands/chat.py +38 -0
  125. QuantNodes/cli/commands/evolve.py +120 -0
  126. QuantNodes/cli/commands/factor.py +569 -0
  127. QuantNodes/cli/commands/init.py +190 -0
  128. QuantNodes/cli/commands/run.py +259 -0
  129. QuantNodes/cli/commands/serve.py +398 -0
  130. QuantNodes/cli/commands/version.py +120 -0
  131. QuantNodes/cli/enhanced.py +146 -0
  132. QuantNodes/conf_node/__init__.py +37 -0
  133. QuantNodes/conf_node/base.py +120 -0
  134. QuantNodes/conf_node/env_config.py +132 -0
  135. QuantNodes/conf_node/ini_config.py +70 -0
  136. QuantNodes/conf_node/json_config.py +69 -0
  137. QuantNodes/conf_node/yaml_config.py +78 -0
  138. QuantNodes/constants.py +17 -0
  139. QuantNodes/core/__init__.py +196 -0
  140. QuantNodes/core/_lookback_helpers.py +49 -0
  141. QuantNodes/core/ast_parser.py +198 -0
  142. QuantNodes/core/base.py +61 -0
  143. QuantNodes/core/cache_manager.py +344 -0
  144. QuantNodes/core/cache_utils.py +150 -0
  145. QuantNodes/core/cond_builder.py +53 -0
  146. QuantNodes/core/config.py +170 -0
  147. QuantNodes/core/constants.py +48 -0
  148. QuantNodes/core/control.py +412 -0
  149. QuantNodes/core/data_preprocessing.py +453 -0
  150. QuantNodes/core/data_source.py +46 -0
  151. QuantNodes/core/events.py +178 -0
  152. QuantNodes/core/evolution/__init__.py +22 -0
  153. QuantNodes/core/evolution/loop.py +583 -0
  154. QuantNodes/core/evolution/operators.py +289 -0
  155. QuantNodes/core/evolution/settings.py +44 -0
  156. QuantNodes/core/expression.py +841 -0
  157. QuantNodes/core/feedback/__init__.py +38 -0
  158. QuantNodes/core/feedback/channels.py +182 -0
  159. QuantNodes/core/feedback/collector.py +91 -0
  160. QuantNodes/core/feedback/dataclass.py +239 -0
  161. QuantNodes/core/feedback/llm_judge.py +138 -0
  162. QuantNodes/core/knowledge/__init__.py +69 -0
  163. QuantNodes/core/knowledge/knowledge_base.py +217 -0
  164. QuantNodes/core/knowledge/lineage_compress.py +196 -0
  165. QuantNodes/core/knowledge/lineage_expand.py +123 -0
  166. QuantNodes/core/knowledge/metrics/__init__.py +43 -0
  167. QuantNodes/core/knowledge/metrics/evaluator.py +176 -0
  168. QuantNodes/core/knowledge/metrics/metrics.py +220 -0
  169. QuantNodes/core/knowledge/rag_prompt.py +196 -0
  170. QuantNodes/core/knowledge/retriever.py +209 -0
  171. QuantNodes/core/lambda_node.py +81 -0
  172. QuantNodes/core/monitoring/__init__.py +22 -0
  173. QuantNodes/core/monitoring/collector.py +292 -0
  174. QuantNodes/core/monitoring/dashboard.py +365 -0
  175. QuantNodes/core/node.py +375 -0
  176. QuantNodes/core/pandas_utils.py +504 -0
  177. QuantNodes/core/parallel/__init__.py +15 -0
  178. QuantNodes/core/parallel/worker.py +140 -0
  179. QuantNodes/core/parallel/worker_process.py +265 -0
  180. QuantNodes/core/path_utils.py +73 -0
  181. QuantNodes/core/pipeline.py +328 -0
  182. QuantNodes/core/plugin.py +135 -0
  183. QuantNodes/core/quality_gate/__init__.py +32 -0
  184. QuantNodes/core/quality_gate/complexity.py +94 -0
  185. QuantNodes/core/quality_gate/consistency.py +26 -0
  186. QuantNodes/core/quality_gate/node.py +97 -0
  187. QuantNodes/core/quality_gate/redundancy.py +51 -0
  188. QuantNodes/core/quality_gate/settings.py +43 -0
  189. QuantNodes/core/quality_gate/zoo.py +98 -0
  190. QuantNodes/core/serializable.py +116 -0
  191. QuantNodes/core/serialization.py +673 -0
  192. QuantNodes/core/tools.py +333 -0
  193. QuantNodes/core/trajectory/__init__.py +25 -0
  194. QuantNodes/core/trajectory/entry.py +116 -0
  195. QuantNodes/core/trajectory/lineage.py +67 -0
  196. QuantNodes/core/trajectory/pool.py +211 -0
  197. QuantNodes/core/trajectory/selector.py +140 -0
  198. QuantNodes/core/visualization/__init__.py +33 -0
  199. QuantNodes/core/visualization/builder.py +233 -0
  200. QuantNodes/core/visualization/gate_breakdown.py +140 -0
  201. QuantNodes/core/visualization/lineage_dag.py +203 -0
  202. QuantNodes/core/visualization/metric_distribution.py +125 -0
  203. QuantNodes/core/visualization/report.py +68 -0
  204. QuantNodes/database_node/__init__.py +69 -0
  205. QuantNodes/database_node/base.py +135 -0
  206. QuantNodes/database_node/clickhouse_node.py +272 -0
  207. QuantNodes/database_node/csv_node.py +83 -0
  208. QuantNodes/database_node/duckdb_node.py +86 -0
  209. QuantNodes/database_node/factory.py +83 -0
  210. QuantNodes/database_node/mysql_node.py +100 -0
  211. QuantNodes/database_node/parquet_node.py +75 -0
  212. QuantNodes/database_node/sqlite_node.py +67 -0
  213. QuantNodes/factor_node/__init__.py +50 -0
  214. QuantNodes/factor_node/factor.py +563 -0
  215. QuantNodes/factor_node/factor_db.py +421 -0
  216. QuantNodes/factor_node/factor_functions/__init__.py +252 -0
  217. QuantNodes/factor_node/factor_functions/_helpers.py +358 -0
  218. QuantNodes/factor_node/factor_functions/_helpers_debug.py +317 -0
  219. QuantNodes/factor_node/factor_functions/composite_ops.py +136 -0
  220. QuantNodes/factor_node/factor_functions/math_ops.py +433 -0
  221. QuantNodes/factor_node/factor_functions/section_ops.py +290 -0
  222. QuantNodes/factor_node/factor_functions/talib_ops.py +1293 -0
  223. QuantNodes/factor_node/factor_functions/time_ops.py +535 -0
  224. QuantNodes/factor_node/factor_operation.py +1115 -0
  225. QuantNodes/factor_node/factor_table.py +1073 -0
  226. QuantNodes/factor_node/quant_nodes_object.py +60 -0
  227. QuantNodes/mcp_server/__init__.py +27 -0
  228. QuantNodes/mcp_server/__main__.py +4 -0
  229. QuantNodes/mcp_server/server.py +272 -0
  230. QuantNodes/methods/__init__.py +28 -0
  231. QuantNodes/methods/pipeline.py +100 -0
  232. QuantNodes/methods/sandbox.py +102 -0
  233. QuantNodes/monitor/__init__.py +27 -0
  234. QuantNodes/monitor/agent_tools/__init__.py +5 -0
  235. QuantNodes/monitor/agent_tools/monitor_tool.py +98 -0
  236. QuantNodes/monitor/agent_tools/schedule_tool.py +98 -0
  237. QuantNodes/monitor/agent_tools/version_tool.py +133 -0
  238. QuantNodes/monitor/monitor/__init__.py +6 -0
  239. QuantNodes/monitor/monitor/alerter.py +60 -0
  240. QuantNodes/monitor/monitor/collector.py +164 -0
  241. QuantNodes/monitor/monitor/dashboard.py +115 -0
  242. QuantNodes/monitor/monitor/drift.py +190 -0
  243. QuantNodes/monitor/scheduler/__init__.py +4 -0
  244. QuantNodes/monitor/scheduler/runner.py +133 -0
  245. QuantNodes/monitor/scheduler/scheduler.py +184 -0
  246. QuantNodes/monitor/storage/__init__.py +16 -0
  247. QuantNodes/monitor/storage/models.py +70 -0
  248. QuantNodes/monitor/storage/repository.py +407 -0
  249. QuantNodes/monitor/version/__init__.py +4 -0
  250. QuantNodes/monitor/version/diff.py +81 -0
  251. QuantNodes/monitor/version/version_manager.py +182 -0
  252. QuantNodes/operator_node/__init__.py +28 -0
  253. QuantNodes/operator_node/base.py +97 -0
  254. QuantNodes/operator_node/query_node.py +129 -0
  255. QuantNodes/operator_node/sql_builder.py +125 -0
  256. QuantNodes/operator_node/sql_utils.py +172 -0
  257. QuantNodes/operator_node/transform.py +130 -0
  258. QuantNodes/operators/__init__.py +90 -0
  259. QuantNodes/operators/_engine.py +108 -0
  260. QuantNodes/operators/composite.py +161 -0
  261. QuantNodes/operators/composite_dag.py +667 -0
  262. QuantNodes/operators/composite_dag_ops.py +343 -0
  263. QuantNodes/operators/composite_dag_pandas_ops.py +382 -0
  264. QuantNodes/operators/custom.py +408 -0
  265. QuantNodes/operators/facade.py +164 -0
  266. QuantNodes/operators/math.py +163 -0
  267. QuantNodes/operators/proxy.py +29 -0
  268. QuantNodes/operators/registry.py +144 -0
  269. QuantNodes/operators/section.py +99 -0
  270. QuantNodes/operators/talib.py +757 -0
  271. QuantNodes/operators/templates.py +95 -0
  272. QuantNodes/operators/time_series.py +136 -0
  273. QuantNodes/prompts/__init__.py +20 -0
  274. QuantNodes/prompts/backtest/__init__.py +12 -0
  275. QuantNodes/prompts/backtest/factor_based.py +86 -0
  276. QuantNodes/prompts/backtest/standard.py +73 -0
  277. QuantNodes/prompts/factor/__init__.py +14 -0
  278. QuantNodes/prompts/factor/correlation.py +77 -0
  279. QuantNodes/prompts/factor/group_backtest.py +86 -0
  280. QuantNodes/prompts/factor/ic_analysis.py +91 -0
  281. QuantNodes/prompts/strategy/__init__.py +18 -0
  282. QuantNodes/prompts/strategy/market_neutral.py +96 -0
  283. QuantNodes/prompts/strategy/mean_reversion.py +107 -0
  284. QuantNodes/prompts/strategy/momentum.py +160 -0
  285. QuantNodes/prompts/strategy/pairs_trading.py +107 -0
  286. QuantNodes/prompts/strategy/trend_following.py +96 -0
  287. QuantNodes/research/README.md +106 -0
  288. QuantNodes/research/__init__.py +154 -0
  289. QuantNodes/research/_legacy_3c/__init__.py +61 -0
  290. QuantNodes/research/_legacy_3c/auto_researcher.py +289 -0
  291. QuantNodes/research/_legacy_3c/factor_evaluator.py +560 -0
  292. QuantNodes/research/_legacy_3c/factor_miner.py +318 -0
  293. QuantNodes/research/_legacy_3c/mcts_search.py +324 -0
  294. QuantNodes/research/factor_test/__init__.py +25 -0
  295. QuantNodes/research/factor_test/config.py +184 -0
  296. QuantNodes/research/factor_test/config_builder.py +276 -0
  297. QuantNodes/research/factor_test/e2e/data_prep.py +163 -0
  298. QuantNodes/research/factor_test/e2e/run_evolution_e2e.py +309 -0
  299. QuantNodes/research/factor_test/evolution_adapter.py +231 -0
  300. QuantNodes/research/factor_test/feedback_wrapper.py +102 -0
  301. QuantNodes/research/factor_test/ifind_db/__init__.py +7 -0
  302. QuantNodes/research/factor_test/ifind_db/fetcher.py +224 -0
  303. QuantNodes/research/factor_test/ifind_db/ifind_database.py +689 -0
  304. QuantNodes/research/factor_test/nodes/__init__.py +1 -0
  305. QuantNodes/research/factor_test/nodes/_base.py +91 -0
  306. QuantNodes/research/factor_test/nodes/adjust_date_node.py +48 -0
  307. QuantNodes/research/factor_test/nodes/configs.py +240 -0
  308. QuantNodes/research/factor_test/nodes/factor_neutralize_node.py +87 -0
  309. QuantNodes/research/factor_test/nodes/factor_preprocess_node.py +222 -0
  310. QuantNodes/research/factor_test/nodes/factor_score_node.py +141 -0
  311. QuantNodes/research/factor_test/nodes/factor_test_report_node.py +153 -0
  312. QuantNodes/research/factor_test/nodes/group_analyzer_node.py +317 -0
  313. QuantNodes/research/factor_test/nodes/ic_analyzer_node.py +112 -0
  314. QuantNodes/research/factor_test/nodes/load_data_node.py +100 -0
  315. QuantNodes/research/factor_test/nodes/long_short_node.py +93 -0
  316. QuantNodes/research/factor_test/nodes/neutralizers.py +222 -0
  317. QuantNodes/research/factor_test/nodes/preprocess_strategies.py +277 -0
  318. QuantNodes/research/factor_test/nodes/risk_correlation_node.py +112 -0
  319. QuantNodes/research/factor_test/nodes/sample_pool_filter_node.py +110 -0
  320. QuantNodes/research/factor_test/nodes/tradability_filter_node.py +92 -0
  321. QuantNodes/research/factor_test/pipeline_runner.py +305 -0
  322. QuantNodes/research/factor_test/pipeline_spec.py +216 -0
  323. QuantNodes/research/factor_test/utils/__init__.py +26 -0
  324. QuantNodes/research/factor_test/utils/constants.py +86 -0
  325. QuantNodes/research/factor_test/utils/data_loader.py +141 -0
  326. QuantNodes/research/factor_test/utils/date_utils.py +232 -0
  327. QuantNodes/research/factor_test/utils/file_loaders.py +150 -0
  328. QuantNodes/research/factor_test/utils/labels.py +37 -0
  329. QuantNodes/research/factor_test/utils/metrics_extractor.py +55 -0
  330. QuantNodes/research/factor_test/utils/performance_metrics.py +175 -0
  331. QuantNodes/research/factor_test/utils/safe_load.py +106 -0
  332. QuantNodes/research/quant_alpha/CHANGELOG.md +80 -0
  333. QuantNodes/research/quant_alpha/README.md +142 -0
  334. QuantNodes/research/quant_alpha/__init__.py +45 -0
  335. QuantNodes/research/quant_alpha/adapters/__init__.py +99 -0
  336. QuantNodes/research/quant_alpha/adapters/calculator.py +503 -0
  337. QuantNodes/research/quant_alpha/adapters/expression.py +387 -0
  338. QuantNodes/research/quant_alpha/alpha101_design/__init__.py +50 -0
  339. QuantNodes/research/quant_alpha/alpha101_design/few_shot_examples.py +243 -0
  340. QuantNodes/research/quant_alpha/alpha101_design/philosophy.py +474 -0
  341. QuantNodes/research/quant_alpha/alpha158_design/__init__.py +63 -0
  342. QuantNodes/research/quant_alpha/alpha158_design/few_shot_examples.py +219 -0
  343. QuantNodes/research/quant_alpha/alpha158_design/philosophy.py +240 -0
  344. QuantNodes/research/quant_alpha/evaluation/__init__.py +47 -0
  345. QuantNodes/research/quant_alpha/evaluation/baselines/__init__.py +8 -0
  346. QuantNodes/research/quant_alpha/evaluation/baselines/g1_handcrafted.py +135 -0
  347. QuantNodes/research/quant_alpha/evaluation/baselines/g2_llm_only.py +269 -0
  348. QuantNodes/research/quant_alpha/evaluation/baselines/g3_alpha_gpt.py +152 -0
  349. QuantNodes/research/quant_alpha/evaluation/clickhouse_data_loader.py +227 -0
  350. QuantNodes/research/quant_alpha/evaluation/contracts.py +376 -0
  351. QuantNodes/research/quant_alpha/evaluation/evaluators/__init__.py +6 -0
  352. QuantNodes/research/quant_alpha/evaluation/evaluators/polars_evaluator.py +545 -0
  353. QuantNodes/research/quant_alpha/evaluation/mock_data_loader.py +226 -0
  354. QuantNodes/research/quant_alpha/evaluation/runner.py +243 -0
  355. QuantNodes/research/quant_alpha/llm/__init__.py +38 -0
  356. QuantNodes/research/quant_alpha/llm/parser.py +681 -0
  357. QuantNodes/research/quant_alpha/logic_driven_pipeline.py +411 -0
  358. QuantNodes/research/quant_alpha/logic_mining/__init__.py +74 -0
  359. QuantNodes/research/quant_alpha/logic_mining/compiler.py +457 -0
  360. QuantNodes/research/quant_alpha/logic_mining/generator.py +366 -0
  361. QuantNodes/research/quant_alpha/logic_mining/models.py +252 -0
  362. QuantNodes/research/quant_alpha/logic_mining/parser.py +287 -0
  363. QuantNodes/research/quant_alpha/logic_mining/pipelines.py +297 -0
  364. QuantNodes/research/quant_alpha/logic_mining/sources.py +149 -0
  365. QuantNodes/research/quant_alpha/mcts/__init__.py +66 -0
  366. QuantNodes/research/quant_alpha/mcts/cache.py +262 -0
  367. QuantNodes/research/quant_alpha/mcts/extension_ops.py +320 -0
  368. QuantNodes/research/quant_alpha/mcts/feedback.py +825 -0
  369. QuantNodes/research/quant_alpha/mcts/op_prior.py +180 -0
  370. QuantNodes/research/quant_alpha/mcts/search.py +540 -0
  371. QuantNodes/research/quant_alpha/mcts/tree.py +201 -0
  372. QuantNodes/research/quant_alpha/operator_vocab/__init__.py +50 -0
  373. QuantNodes/research/quant_alpha/operator_vocab/config.py +54 -0
  374. QuantNodes/research/quant_alpha/operator_vocab/metadata.py +263 -0
  375. QuantNodes/research/quant_alpha/operator_vocab/vocabulary.py +481 -0
  376. QuantNodes/research/quant_alpha/pipeline.py +1027 -0
  377. QuantNodes/research/quant_alpha/types/__init__.py +27 -0
  378. QuantNodes/research/quant_alpha/types/constants.py +28 -0
  379. QuantNodes/research/quant_alpha/types/state.py +205 -0
  380. QuantNodes/research/quant_alpha/workflow/__init__.py +32 -0
  381. QuantNodes/research/quant_alpha/workflow/alpha_gpt.py +911 -0
  382. QuantNodes/research/quant_alpha/workflow/alpha_logics.py +416 -0
  383. QuantNodes/research/quant_alpha/workflow/state.py +27 -0
  384. QuantNodes/research/report_reproducer.py +485 -0
  385. QuantNodes/research/wiki.py +1155 -0
  386. QuantNodes/symbolic/__init__.py +51 -0
  387. QuantNodes/symbolic/compiler.py +113 -0
  388. QuantNodes/symbolic/dialect.py +260 -0
  389. QuantNodes/symbolic/executor.py +147 -0
  390. QuantNodes/symbolic/expression.py +234 -0
  391. QuantNodes/symbolic/functions.py +433 -0
  392. QuantNodes/symbolic/optimizer.py +165 -0
  393. QuantNodes/ui_node/__init__.py +30 -0
  394. QuantNodes/ui_node/base.py +222 -0
  395. quantnodes-3.0.0.dist-info/METADATA +463 -0
  396. quantnodes-3.0.0.dist-info/RECORD +399 -0
  397. quantnodes-3.0.0.dist-info/WHEEL +5 -0
  398. quantnodes-3.0.0.dist-info/entry_points.txt +24 -0
  399. quantnodes-3.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,49 @@
1
+ # -*- coding: utf-8 -*-
2
+ """LookBack 窗口计算的共用辅助函数"""
3
+ import numpy as np
4
+
5
+
6
+ def compute_lookback_params(lookback, lookback_mode):
7
+ """计算 LookBack 窗口参数
8
+
9
+ Args:
10
+ lookback: list of lookback values for descriptors
11
+ lookback_mode: list of lookback modes for descriptors
12
+
13
+ Returns:
14
+ tuple: (StartIndAndLen, MaxLookBack, MaxLen)
15
+ - StartIndAndLen: list of (start_ind, length) tuples
16
+ - MaxLookBack: maximum lookback value
17
+ - MaxLen: maximum window length
18
+ """
19
+ StartIndAndLen, MaxLookBack, MaxLen = [], 0, 1
20
+ for i, iLookBack in enumerate(lookback):
21
+ if lookback_mode[i] == "滚动窗口":
22
+ StartIndAndLen.append((iLookBack, iLookBack + 1))
23
+ MaxLen = max(MaxLen, iLookBack + 1)
24
+ else:
25
+ StartIndAndLen.append((iLookBack, np.inf))
26
+ MaxLen = np.inf
27
+ MaxLookBack = max(MaxLookBack, iLookBack)
28
+ return StartIndAndLen, MaxLookBack, MaxLen
29
+
30
+
31
+ def extend_dt_ruler(dt_ruler, dts, max_lookback):
32
+ """扩展时间标尺向前回溯
33
+
34
+ 如果 start_ind >= max_lookback,直接返回 dt_ruler[start_ind-max_lookback:]
35
+ 否则在前面补 None 凑够 max_lookback 个。
36
+
37
+ Args:
38
+ dt_ruler: 时间标尺
39
+ dts: 当前时间序列
40
+ max_lookback: 最大回溯值
41
+
42
+ Returns:
43
+ list: 扩展后的时间标尺
44
+ """
45
+ start_ind = dt_ruler.index(dts[0]) if dts[0] in dt_ruler else 0
46
+ if start_ind >= max_lookback:
47
+ return list(dt_ruler[start_ind - max_lookback:])
48
+ else:
49
+ return [None] * (max_lookback - start_ind) + list(dt_ruler)
@@ -0,0 +1,198 @@
1
+ # coding=utf-8
2
+ """
3
+ AST 安全表达式解析器
4
+
5
+ 基于 Python 标准库的 ast 模块,安全解析表达式字符串,
6
+ 不使用 eval,避免代码注入风险。
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import ast
12
+ import logging
13
+
14
+ from QuantNodes.core.expression import (
15
+ Expression,
16
+ InputExpr,
17
+ ConstantExpr,
18
+ VariableExpr,
19
+ AttributeExpr,
20
+ SubscriptExpr,
21
+ MethodCallExpr,
22
+ BinaryOpExpr,
23
+ UnaryOpExpr,
24
+ ComparisonExpr,
25
+ LogicalOpExpr,
26
+ ALLOWED_AST_NODES,
27
+ FORBIDDEN_METHODS,
28
+ )
29
+
30
+
31
+ logger = logging.getLogger(__name__)
32
+
33
+
34
+ def parse_expression(expr_str: str) -> Expression:
35
+ """
36
+ 安全解析字符串表达式
37
+
38
+ Args:
39
+ expr_str: 表达式字符串,如 "df['close'] > 50"
40
+
41
+ Returns:
42
+ Expression 对象
43
+
44
+ Raises:
45
+ SyntaxError: 表达式语法错误
46
+ ValueError: 包含不支持的操作
47
+ """
48
+ try:
49
+ tree = ast.parse(expr_str, mode="eval")
50
+ except SyntaxError as e:
51
+ raise SyntaxError(f"Invalid expression syntax: {e}") from e
52
+
53
+ # 安全检查
54
+ _validate_ast(tree)
55
+
56
+ # 转换为表达式对象
57
+ return _ast_to_expr(tree.body)
58
+
59
+
60
+ def _validate_ast(node: ast.AST) -> None:
61
+ """递归验证 AST 节点是否在白名单中"""
62
+ if type(node) not in ALLOWED_AST_NODES:
63
+ raise ValueError(f"Unsupported AST node type: {type(node).__name__}")
64
+
65
+ for child in ast.iter_child_nodes(node):
66
+ _validate_ast(child)
67
+
68
+
69
+ def _ast_to_expr(node: ast.AST) -> Expression:
70
+ """将 AST 节点转换为 Expression 对象"""
71
+
72
+ # 常量
73
+ if isinstance(node, ast.Constant):
74
+ return ConstantExpr(node.value)
75
+
76
+ # 变量名 - 假设是输入数据的属性或列名
77
+ if isinstance(node, ast.Name):
78
+ # 特殊处理常见的输入变量名
79
+ if node.id in ("df", "input", "data", "x", "result"):
80
+ return InputExpr()
81
+ # 其他名称视为属性访问
82
+ return VariableExpr(node.id)
83
+
84
+ # 属性访问
85
+ if isinstance(node, ast.Attribute):
86
+ expr = _ast_to_expr(node.value)
87
+ return AttributeExpr(expr, node.attr)
88
+
89
+ # 下标访问
90
+ if isinstance(node, ast.Subscript):
91
+ expr = _ast_to_expr(node.value)
92
+ key = _ast_to_expr(node.slice)
93
+ return SubscriptExpr(expr, key)
94
+
95
+ # 方法调用
96
+ if isinstance(node, ast.Call):
97
+ if isinstance(node.func, ast.Attribute):
98
+ expr = _ast_to_expr(node.func.value)
99
+ method_name = node.func.attr
100
+
101
+ if method_name in FORBIDDEN_METHODS:
102
+ raise ValueError(f"Forbidden method: {method_name}")
103
+
104
+ args = tuple(_ast_to_expr(arg) for arg in node.args)
105
+ kwargs = {
106
+ kw.arg: _ast_to_expr(kw.value)
107
+ for kw in node.keywords
108
+ if kw.arg is not None
109
+ }
110
+ return MethodCallExpr(expr, method_name, args, kwargs)
111
+ raise ValueError("Unsupported call type")
112
+
113
+ # 二元运算
114
+ if isinstance(node, ast.BinOp):
115
+ left = _ast_to_expr(node.left)
116
+ right = _ast_to_expr(node.right)
117
+ op = _bin_op_to_str(node.op)
118
+ return BinaryOpExpr(left, op, right)
119
+
120
+ # 一元运算
121
+ if isinstance(node, ast.UnaryOp):
122
+ operand = _ast_to_expr(node.operand)
123
+ op = _unary_op_to_str(node.op)
124
+ return UnaryOpExpr(op, operand)
125
+
126
+ # 比较运算
127
+ if isinstance(node, ast.Compare):
128
+ left = _ast_to_expr(node.left)
129
+ # 简化:只处理单个比较
130
+ op = _cmp_op_to_str(node.ops[0])
131
+ right = _ast_to_expr(node.comparators[0])
132
+ return ComparisonExpr(left, op, right)
133
+
134
+ # 逻辑运算
135
+ if isinstance(node, ast.BoolOp):
136
+ op = _bool_op_to_str(node.op)
137
+ operands = tuple(_ast_to_expr(v) for v in node.values)
138
+ return LogicalOpExpr(op, *operands)
139
+
140
+ raise ValueError(f"Unsupported AST node: {type(node).__name__}")
141
+
142
+
143
+ def _bin_op_to_str(op: ast.operator) -> str:
144
+ """将二元运算 AST 节点转换为运算符字符串"""
145
+ mapping = {
146
+ ast.Add: "+",
147
+ ast.Sub: "-",
148
+ ast.Mult: "*",
149
+ ast.Div: "/",
150
+ ast.FloorDiv: "//",
151
+ ast.Mod: "%",
152
+ ast.Pow: "**",
153
+ }
154
+ result = mapping.get(type(op))
155
+ if result is None:
156
+ raise ValueError(f"Unsupported binary operator: {type(op).__name__}")
157
+ return result
158
+
159
+
160
+ def _unary_op_to_str(op: ast.unaryop) -> str:
161
+ """将一元运算 AST 节点转换为运算符字符串"""
162
+ mapping = {
163
+ ast.UAdd: "+",
164
+ ast.USub: "-",
165
+ ast.Not: "not",
166
+ }
167
+ result = mapping.get(type(op))
168
+ if result is None:
169
+ raise ValueError(f"Unsupported unary operator: {type(op).__name__}")
170
+ return result
171
+
172
+
173
+ def _cmp_op_to_str(op: ast.cmpop) -> str:
174
+ """将比较运算 AST 节点转换为运算符字符串"""
175
+ mapping = {
176
+ ast.Gt: ">",
177
+ ast.GtE: ">=",
178
+ ast.Lt: "<",
179
+ ast.LtE: "<=",
180
+ ast.Eq: "==",
181
+ ast.NotEq: "!=",
182
+ }
183
+ result = mapping.get(type(op))
184
+ if result is None:
185
+ raise ValueError(f"Unsupported comparison operator: {type(op).__name__}")
186
+ return result
187
+
188
+
189
+ def _bool_op_to_str(op: ast.boolop) -> str:
190
+ """将逻辑运算 AST 节点转换为运算符字符串"""
191
+ mapping = {
192
+ ast.And: "and",
193
+ ast.Or: "or",
194
+ }
195
+ result = mapping.get(type(op))
196
+ if result is None:
197
+ raise ValueError(f"Unsupported logical operator: {type(op).__name__}")
198
+ return result
@@ -0,0 +1,61 @@
1
+ # coding=utf-8
2
+
3
+ from typing import Any, Dict, Optional
4
+ from pydantic import BaseModel as PydanticBaseModel, ConfigDict
5
+
6
+
7
+ class BaseModel(PydanticBaseModel):
8
+ """基础模型类"""
9
+ model_config = ConfigDict(
10
+ arbitrary_types_allowed=True,
11
+ extra="forbid",
12
+ frozen=False,
13
+ )
14
+
15
+
16
+ class QuantNodesBase:
17
+ """所有业务类的基类"""
18
+
19
+ def __init__(self, name: Optional[str] = None):
20
+ self.name = name or self.__class__.__name__
21
+
22
+ def __repr__(self) -> str:
23
+ return f"<{self.__class__.__name__}: {self.name}>"
24
+
25
+
26
+ class QuantNodesError(Exception):
27
+ """基础异常类"""
28
+ code = "QUANTNODES_ERROR"
29
+
30
+ def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):
31
+ super().__init__(message)
32
+ self.message = message
33
+ self.details = details or {}
34
+
35
+ def __str__(self) -> str:
36
+ return f"[{self.code}] {self.message}"
37
+
38
+
39
+ class ConfigError(QuantNodesError):
40
+ """配置异常"""
41
+ code = "CONFIG_ERROR"
42
+
43
+
44
+ class DatabaseError(QuantNodesError):
45
+ """数据库异常"""
46
+ code = "DATABASE_ERROR"
47
+
48
+
49
+ class FactorError(QuantNodesError):
50
+ """因子异常"""
51
+ code = "FACTOR_ERROR"
52
+
53
+
54
+ class BacktestError(QuantNodesError):
55
+ """回测异常"""
56
+ code = "BACKTEST_ERROR"
57
+
58
+
59
+ class ValidationError(QuantNodesError):
60
+ """校验异常"""
61
+ code = "VALIDATION_ERROR"
@@ -0,0 +1,344 @@
1
+ # coding=utf-8
2
+ """
3
+ 缓存管理器
4
+
5
+ 替代 QuantStudio 中与缓存和进程管理相关的功能
6
+ """
7
+
8
+ import gc
9
+ import mmap
10
+ import os
11
+ import pickle
12
+ import shelve
13
+ from multiprocessing import Lock
14
+ from typing import Any, Dict, List, Optional
15
+
16
+ import pandas as pd
17
+
18
+ from QuantNodes.core.tools import get_shelve_file_suffix
19
+
20
+
21
+ class ErgodicMode:
22
+ """
23
+ 遍历模式参数对象
24
+
25
+ 管理因子遍历模式下的缓存策略
26
+ """
27
+
28
+ def __init__(
29
+ self,
30
+ forward_period: int = 600,
31
+ backward_period: int = 1,
32
+ cache_mode: str = "因子",
33
+ max_factor_cache_num: int = 60,
34
+ max_id_cache_num: int = 10000,
35
+ cache_size: int = 300,
36
+ ergodic_dts: Optional[List] = None,
37
+ ergodic_ids: Optional[List] = None,
38
+ ):
39
+ self.ForwardPeriod = forward_period
40
+ self.BackwardPeriod = backward_period
41
+ self.CacheMode = cache_mode
42
+ self.MaxFactorCacheNum = max_factor_cache_num
43
+ self.MaxIDCacheNum = max_id_cache_num
44
+ self.CacheSize = cache_size
45
+ self.ErgodicDTs = ergodic_dts or []
46
+ self.ErgodicIDs = ergodic_ids or []
47
+ self._isStarted = False
48
+ self._CurDT = None
49
+ self._DateTimes = None
50
+ self._IDs = None
51
+ self._CurInd = None
52
+ self._DTNum = None
53
+ self._CacheDTs = None
54
+ self._CacheData = None
55
+ self._CacheFactorNum = None
56
+ self._CacheIDNum = None
57
+ self._FactorReadNum = None
58
+ self._IDReadNum = None
59
+ self._Queue2SubProcess = None
60
+ self._Queue2MainProcess = None
61
+ self._TagName = None
62
+ self._MMAPCacheData = None
63
+ self._CacheDataProcess = None
64
+
65
+ def __getstate__(self):
66
+ state = self.__dict__.copy()
67
+ if "_CacheDataProcess" in state:
68
+ state["_CacheDataProcess"] = None
69
+ return state
70
+
71
+
72
+ class OperationMode:
73
+ """
74
+ 运算模式参数对象
75
+
76
+ 管理因子运算模式下的多进程调度
77
+ """
78
+
79
+ def __init__(
80
+ self,
81
+ ft: Any = None,
82
+ factor_names: Optional[List[str]] = None,
83
+ subprocess_num: int = 0,
84
+ ):
85
+ self._FT = ft
86
+ self._isStarted = False
87
+ self._Factors = []
88
+ self._FactorDict = {}
89
+ self._FactorID = {}
90
+ self._FactorStartDT = {}
91
+ self._FactorPrepareIDs = {}
92
+ self._iPID = "0"
93
+ self._PIDs = []
94
+ self._PID_IDs = {}
95
+ self._PID_Lock = {}
96
+ self._CacheDir = None
97
+ self._RawDataDir = ""
98
+ self._CacheDataDir = ""
99
+ self._Event = {}
100
+ self._DateTimes = []
101
+ self._IDs = []
102
+ self._DTRuler = []
103
+ self.SubProcessNum = subprocess_num
104
+ self.FactorNames = factor_names or []
105
+ self.FileSuffix = get_shelve_file_suffix()
106
+ if self.FileSuffix:
107
+ self.FileSuffix = "." + self.FileSuffix
108
+
109
+ def __getstate__(self):
110
+ state = self.__dict__.copy()
111
+ if self._CacheDir is not None:
112
+ state["_CacheDir"] = self._CacheDir.name
113
+ return state
114
+
115
+
116
+ def prepare_mmap_factor_cache_data(ft: Any, mmap_cache: Any) -> int:
117
+ """
118
+ 基于 mmap 的因子缓冲数据准备子进程
119
+ """
120
+ CacheData = {}
121
+ CacheDTs = []
122
+ CacheSize = int(ft.ErgodicMode.CacheSize * 2**20)
123
+
124
+ if os.name == "nt":
125
+ MMAPCacheData = mmap.mmap(-1, CacheSize, tagname=ft.ErgodicMode._TagName)
126
+ else:
127
+ MMAPCacheData = mmap_cache
128
+
129
+ while True:
130
+ Task = ft.ErgodicMode._Queue2SubProcess.get()
131
+ if Task is None:
132
+ break
133
+
134
+ if Task[0] is None and Task[1] is None:
135
+ CacheDataByte = pickle.dumps(CacheData)
136
+ DataLen = len(CacheDataByte)
137
+ for i in range(int(DataLen / CacheSize) + 1):
138
+ iStartInd = i * CacheSize
139
+ iEndInd = min((i + 1) * CacheSize, DataLen)
140
+ if iEndInd > iStartInd:
141
+ MMAPCacheData.seek(0)
142
+ MMAPCacheData.write(CacheDataByte[iStartInd:iEndInd])
143
+ ft.ErgodicMode._Queue2MainProcess.put(iEndInd - iStartInd)
144
+ ft.ErgodicMode._Queue2SubProcess.get()
145
+ ft.ErgodicMode._Queue2MainProcess.put(0)
146
+ del CacheDataByte
147
+ gc.collect()
148
+ elif Task[0] is None:
149
+ NewFactors, PopFactors = Task[1]
150
+ for iFactorName in PopFactors:
151
+ CacheData.pop(iFactorName)
152
+ if NewFactors:
153
+ if CacheDTs:
154
+ CacheData.update(
155
+ dict(
156
+ ft.__QN_calc_data__(
157
+ raw_data=ft.__QN_prepare_raw_data__(
158
+ factor_names=NewFactors,
159
+ ids=ft.ErgodicMode._IDs,
160
+ dts=CacheDTs,
161
+ ),
162
+ factor_names=NewFactors,
163
+ ids=ft.ErgodicMode._IDs,
164
+ dts=CacheDTs,
165
+ )
166
+ )
167
+ )
168
+ else:
169
+ CacheData.update(
170
+ {
171
+ iFactorName: pd.DataFrame(index=CacheDTs, columns=ft.ErgodicMode._IDs)
172
+ for iFactorName in NewFactors
173
+ }
174
+ )
175
+ else:
176
+ CurInd = Task[0] + ft.ErgodicMode.ForwardPeriod + 1
177
+ DTNum = len(ft.ErgodicMode._DateTimes)
178
+ if CurInd < DTNum:
179
+ OldCacheDTs = set(CacheDTs)
180
+ CacheDTs = ft.ErgodicMode._DateTimes[
181
+ max((0, CurInd - ft.ErgodicMode.BackwardPeriod)) : min(
182
+ (DTNum, CurInd + ft.ErgodicMode.ForwardPeriod + 1)
183
+ )
184
+ ].tolist()
185
+ NewCacheDTs = sorted(set(CacheDTs).difference(OldCacheDTs))
186
+ if CacheData:
187
+ isDisjoint = OldCacheDTs.isdisjoint(CacheDTs)
188
+ CacheFactorNames = list(CacheData.keys())
189
+ if NewCacheDTs:
190
+ NewCacheData = ft.__QN_calc_data__(
191
+ raw_data=ft.__QN_prepare_raw_data__(
192
+ factor_names=CacheFactorNames,
193
+ ids=ft.ErgodicMode._IDs,
194
+ dts=NewCacheDTs,
195
+ ),
196
+ factor_names=CacheFactorNames,
197
+ ids=ft.ErgodicMode._IDs,
198
+ dts=NewCacheDTs,
199
+ )
200
+ else:
201
+ NewCacheData = pd.DataFrame(
202
+ index=CacheFactorNames, columns=CacheDTs
203
+ )
204
+ for iFactorName in CacheData:
205
+ if isDisjoint:
206
+ CacheData[iFactorName] = NewCacheData[iFactorName]
207
+ else:
208
+ CacheData[iFactorName] = CacheData[iFactorName].loc[CacheDTs, :]
209
+ CacheData[iFactorName].loc[NewCacheDTs, :] = NewCacheData[iFactorName]
210
+ NewCacheData = None
211
+ return 0
212
+
213
+
214
+ def prepare_mmap_id_cache_data(ft: Any, mmap_cache: Any) -> int:
215
+ """
216
+ 基于 mmap 的 ID 缓冲数据准备子进程
217
+ """
218
+ CacheData = {}
219
+ CacheDTs = []
220
+ CacheSize = int(ft.ErgodicMode.CacheSize * 2**20)
221
+
222
+ if os.name == "nt":
223
+ MMAPCacheData = mmap.mmap(-1, CacheSize, tagname=ft.ErgodicMode._TagName)
224
+ else:
225
+ MMAPCacheData = mmap_cache
226
+
227
+ while True:
228
+ Task = ft.ErgodicMode._Queue2SubProcess.get()
229
+ if Task is None:
230
+ break
231
+
232
+ if Task[0] is None and Task[1] is None:
233
+ CacheDataByte = pickle.dumps(CacheData)
234
+ DataLen = len(CacheDataByte)
235
+ for i in range(int(DataLen / CacheSize) + 1):
236
+ iStartInd = i * CacheSize
237
+ iEndInd = min((i + 1) * CacheSize, DataLen)
238
+ if iEndInd > iStartInd:
239
+ MMAPCacheData.seek(0)
240
+ MMAPCacheData.write(CacheDataByte[iStartInd:iEndInd])
241
+ ft.ErgodicMode._Queue2MainProcess.put(iEndInd - iStartInd)
242
+ ft.ErgodicMode._Queue2SubProcess.get()
243
+ ft.ErgodicMode._Queue2MainProcess.put(0)
244
+ del CacheDataByte
245
+ gc.collect()
246
+ elif Task[0] is None:
247
+ NewID, PopID = Task[1]
248
+ if PopID:
249
+ CacheData.pop(PopID)
250
+ if NewID:
251
+ if CacheDTs:
252
+ CacheData[NewID] = ft.__QN_calc_data__(
253
+ raw_data=ft.__QN_prepare_raw_data__(
254
+ factor_names=ft.FactorNames,
255
+ ids=[NewID],
256
+ dts=CacheDTs,
257
+ ),
258
+ factor_names=ft.FactorNames,
259
+ ids=[NewID],
260
+ dts=CacheDTs,
261
+ ).iloc[:, :, 0]
262
+ else:
263
+ CacheData[NewID] = pd.DataFrame(index=CacheDTs, columns=ft.FactorNames)
264
+ else:
265
+ CurInd = Task[0] + ft.ErgodicMode.ForwardPeriod + 1
266
+ DTNum = len(ft.ErgodicMode._DateTimes)
267
+ if CurInd < DTNum:
268
+ OldCacheDTs = set(CacheDTs)
269
+ CacheDTs = ft.ErgodicMode._DateTimes[
270
+ max((0, CurInd - ft.ErgodicMode.BackwardPeriod)) : min(
271
+ (DTNum, CurInd + ft.ErgodicMode.ForwardPeriod + 1)
272
+ )
273
+ ].tolist()
274
+ NewCacheDTs = sorted(set(CacheDTs).difference(OldCacheDTs))
275
+ if CacheData:
276
+ isDisjoint = OldCacheDTs.isdisjoint(CacheDTs)
277
+ CacheIDs = list(CacheData.keys())
278
+ if NewCacheDTs:
279
+ NewCacheData = ft.__QN_calc_data__(
280
+ raw_data=ft.__QN_prepare_raw_data__(
281
+ factor_names=ft.FactorNames,
282
+ ids=CacheIDs,
283
+ dts=NewCacheDTs,
284
+ ),
285
+ factor_names=ft.FactorNames,
286
+ ids=CacheIDs,
287
+ dts=NewCacheDTs,
288
+ )
289
+ else:
290
+ NewCacheData = pd.DataFrame(
291
+ index=ft.FactorNames, columns=CacheDTs
292
+ )
293
+ for iID in CacheData:
294
+ if isDisjoint:
295
+ CacheData[iID] = NewCacheData[iID]
296
+ else:
297
+ CacheData[iID] = CacheData[iID].loc[CacheDTs, :]
298
+ CacheData[iID].loc[NewCacheDTs, :] = NewCacheData[iID]
299
+ NewCacheData = None
300
+ return 0
301
+
302
+
303
+ def save_raw_data(
304
+ raw_data: Any,
305
+ factor_names: List[str],
306
+ raw_data_dir: str,
307
+ pid_ids: Dict[str, List[str]],
308
+ file_name: str,
309
+ pid_lock: Dict[str, Lock],
310
+ ) -> int:
311
+ """
312
+ 保存原始数据到文件
313
+ """
314
+ if raw_data is None:
315
+ return 0
316
+ if isinstance(raw_data, pd.DataFrame) and ("ID" in raw_data):
317
+ raw_data = raw_data.set_index(["ID"])
318
+ CommonCols = raw_data.columns.difference(factor_names).tolist()
319
+ AllIDs = set(raw_data.index)
320
+ for iPID, iIDs in pid_ids.items():
321
+ with shelve.open(raw_data_dir + os.sep + iPID + os.sep + file_name) as iFile:
322
+ iInterIDs = sorted(AllIDs.intersection(iIDs))
323
+ iData = raw_data.loc[iInterIDs]
324
+ if factor_names:
325
+ for jFactorName in factor_names:
326
+ iFile[jFactorName] = iData[CommonCols + [jFactorName]].reset_index()
327
+ else:
328
+ iFile["RawData"] = iData[CommonCols].reset_index()
329
+ iFile["_QN_IDs"] = iIDs
330
+ else:
331
+ for iPID, iIDs in pid_ids.items():
332
+ with shelve.open(raw_data_dir + os.sep + iPID + os.sep + file_name) as iFile:
333
+ iFile["RawData"] = raw_data
334
+ iFile["_QN_IDs"] = iIDs
335
+ return 0
336
+
337
+
338
+ __all__ = [
339
+ "ErgodicMode",
340
+ "OperationMode",
341
+ "prepare_mmap_factor_cache_data",
342
+ "prepare_mmap_id_cache_data",
343
+ "save_raw_data",
344
+ ]