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.
- QuantNodes/__init__.py +15 -0
- QuantNodes/__main__.py +14 -0
- QuantNodes/agent/__init__.py +158 -0
- QuantNodes/agent/agents/__init__.py +13 -0
- QuantNodes/agent/agents/definition.py +180 -0
- QuantNodes/agent/agents/manager.py +73 -0
- QuantNodes/agent/config/__init__.py +34 -0
- QuantNodes/agent/config/executor.py +958 -0
- QuantNodes/agent/config/loader.py +427 -0
- QuantNodes/agent/config/templates/bollinger_bands.yaml +84 -0
- QuantNodes/agent/config/templates/dual_ma.yaml +72 -0
- QuantNodes/agent/config/templates/empty.yaml +56 -0
- QuantNodes/agent/config/templates/mean_reversion.yaml +47 -0
- QuantNodes/agent/config/templates/mean_reversion_zscore.yaml +90 -0
- QuantNodes/agent/config/templates/momentum.yaml +81 -0
- QuantNodes/agent/config/templates/momentum_breakout.yaml +84 -0
- QuantNodes/agent/config/templates/rsi_strategy.yaml +72 -0
- QuantNodes/agent/config/templates/volume_price.yaml +86 -0
- QuantNodes/agent/config/types.py +156 -0
- QuantNodes/agent/config_mapper.py +293 -0
- QuantNodes/agent/core/__init__.py +19 -0
- QuantNodes/agent/core/dream.py +47 -0
- QuantNodes/agent/core/quant_dream.py +274 -0
- QuantNodes/agent/cron_jobs.py +314 -0
- QuantNodes/agent/nanobot_bridge.py +242 -0
- QuantNodes/agent/permission/__init__.py +30 -0
- QuantNodes/agent/permission/defaults.py +36 -0
- QuantNodes/agent/permission/evaluate.py +41 -0
- QuantNodes/agent/permission/models.py +59 -0
- QuantNodes/agent/permission/service.py +133 -0
- QuantNodes/agent/providers/__init__.py +11 -0
- QuantNodes/agent/providers/base.py +102 -0
- QuantNodes/agent/providers/quantnodes.py +610 -0
- QuantNodes/agent/providers/rate_limiter.py +326 -0
- QuantNodes/agent/providers/registry.py +163 -0
- QuantNodes/agent/skills/__init__.py +20 -0
- QuantNodes/agent/skills/base.py +118 -0
- QuantNodes/agent/skills/bridge.py +73 -0
- QuantNodes/agent/skills/factor/__init__.py +14 -0
- QuantNodes/agent/skills/factor/correlation.py +99 -0
- QuantNodes/agent/skills/factor/group_backtest.py +114 -0
- QuantNodes/agent/skills/factor/ic_analysis.py +106 -0
- QuantNodes/agent/skills/loader.py +107 -0
- QuantNodes/agent/skills/registry.py +105 -0
- QuantNodes/agent/skills/strategy/__init__.py +16 -0
- QuantNodes/agent/skills/strategy/bollinger.py +86 -0
- QuantNodes/agent/skills/strategy/dual_ma.py +82 -0
- QuantNodes/agent/skills/strategy/momentum.py +74 -0
- QuantNodes/agent/skills/strategy/rsi_reversal.py +99 -0
- QuantNodes/agent/skills_quant/__init__.py +14 -0
- QuantNodes/agent/skills_quant/backtest-analyze/SKILL.md +42 -0
- QuantNodes/agent/skills_quant/config-driven/SKILL.md +72 -0
- QuantNodes/agent/skills_quant/factor-research/SKILL.md +40 -0
- QuantNodes/agent/skills_quant/quant-dream/SKILL.md +55 -0
- QuantNodes/agent/skills_quant/risk-management/SKILL.md +45 -0
- QuantNodes/agent/skills_quant/strategy-design/SKILL.md +43 -0
- QuantNodes/agent/templates/__init__.py +4 -0
- QuantNodes/agent/tools/__init__.py +173 -0
- QuantNodes/agent/tools/_workspace.py +51 -0
- QuantNodes/agent/tools/alpha_backtest.py +328 -0
- QuantNodes/agent/tools/alpha_evaluate.py +493 -0
- QuantNodes/agent/tools/backtest.py +226 -0
- QuantNodes/agent/tools/base.py +133 -0
- QuantNodes/agent/tools/code_search.py +207 -0
- QuantNodes/agent/tools/config_backtest.py +401 -0
- QuantNodes/agent/tools/context.py +97 -0
- QuantNodes/agent/tools/dream_skill.py +77 -0
- QuantNodes/agent/tools/echo.py +38 -0
- QuantNodes/agent/tools/factor.py +231 -0
- QuantNodes/agent/tools/file_ops.py +201 -0
- QuantNodes/agent/tools/git_ops.py +190 -0
- QuantNodes/agent/tools/operator_lookup.py +218 -0
- QuantNodes/agent/tools/output_truncation.py +77 -0
- QuantNodes/agent/tools/path_check.py +43 -0
- QuantNodes/agent/tools/pipeline.py +62 -0
- QuantNodes/agent/tools/registry.py +150 -0
- QuantNodes/agent/tools/sandbox.py +62 -0
- QuantNodes/agent/tools/shell_safety.py +63 -0
- QuantNodes/agent/tools/strategy.py +106 -0
- QuantNodes/agent/tools/task.py +171 -0
- QuantNodes/agent/tools/web_fetch.py +142 -0
- QuantNodes/agent/tools/web_search.py +114 -0
- QuantNodes/agent/tools/wiki.py +370 -0
- QuantNodes/agent/utils/__init__.py +11 -0
- QuantNodes/agent/utils/helpers.py +43 -0
- QuantNodes/agent/utils/prompt_templates.py +30 -0
- QuantNodes/agent/workflows/__init__.py +20 -0
- QuantNodes/agent/workflows/implementations/__init__.py +8 -0
- QuantNodes/agent/workflows/implementations/alpha_gpt.py +508 -0
- QuantNodes/agent/workflows/implementations/mcts.py +442 -0
- QuantNodes/agent/workflows/parsers.py +44 -0
- QuantNodes/agent/workflows/registry.py +119 -0
- QuantNodes/agent/workflows/step_agent.py +219 -0
- QuantNodes/agent/workflows/tool.py +198 -0
- QuantNodes/ai/__init__.py +93 -0
- QuantNodes/ai/llm/__init__.py +75 -0
- QuantNodes/ai/llm/base.py +233 -0
- QuantNodes/ai/llm/decorators.py +281 -0
- QuantNodes/ai/llm/gateway.py +571 -0
- QuantNodes/ai/llm/null.py +76 -0
- QuantNodes/ai/llm/openai.py +435 -0
- QuantNodes/ai/optimizer.py +405 -0
- QuantNodes/ai/prompts/__init__.py +229 -0
- QuantNodes/ai/sandbox.py +371 -0
- QuantNodes/ai/sandbox_pandas_bridge.py +150 -0
- QuantNodes/ai/strategy_gen.py +396 -0
- QuantNodes/backtest/__init__.py +64 -0
- QuantNodes/backtest/backtest_node.py +188 -0
- QuantNodes/backtest/broker_node.py +378 -0
- QuantNodes/backtest/config_runner.py +397 -0
- QuantNodes/backtest/config_strategy.py +64 -0
- QuantNodes/backtest/risk_node.py +360 -0
- QuantNodes/backtest/strategy_node.py +268 -0
- QuantNodes/cache_node/__init__.py +19 -0
- QuantNodes/cache_node/base.py +244 -0
- QuantNodes/cache_node/cache_store.py +99 -0
- QuantNodes/cache_node/metadata.py +100 -0
- QuantNodes/cli/__init__.py +109 -0
- QuantNodes/cli/_helpers.py +511 -0
- QuantNodes/cli/command.py +110 -0
- QuantNodes/cli/commands/__init__.py +69 -0
- QuantNodes/cli/commands/agent.py +158 -0
- QuantNodes/cli/commands/alpha.py +951 -0
- QuantNodes/cli/commands/chat.py +38 -0
- QuantNodes/cli/commands/evolve.py +120 -0
- QuantNodes/cli/commands/factor.py +569 -0
- QuantNodes/cli/commands/init.py +190 -0
- QuantNodes/cli/commands/run.py +259 -0
- QuantNodes/cli/commands/serve.py +398 -0
- QuantNodes/cli/commands/version.py +120 -0
- QuantNodes/cli/enhanced.py +146 -0
- QuantNodes/conf_node/__init__.py +37 -0
- QuantNodes/conf_node/base.py +120 -0
- QuantNodes/conf_node/env_config.py +132 -0
- QuantNodes/conf_node/ini_config.py +70 -0
- QuantNodes/conf_node/json_config.py +69 -0
- QuantNodes/conf_node/yaml_config.py +78 -0
- QuantNodes/constants.py +17 -0
- QuantNodes/core/__init__.py +196 -0
- QuantNodes/core/_lookback_helpers.py +49 -0
- QuantNodes/core/ast_parser.py +198 -0
- QuantNodes/core/base.py +61 -0
- QuantNodes/core/cache_manager.py +344 -0
- QuantNodes/core/cache_utils.py +150 -0
- QuantNodes/core/cond_builder.py +53 -0
- QuantNodes/core/config.py +170 -0
- QuantNodes/core/constants.py +48 -0
- QuantNodes/core/control.py +412 -0
- QuantNodes/core/data_preprocessing.py +453 -0
- QuantNodes/core/data_source.py +46 -0
- QuantNodes/core/events.py +178 -0
- QuantNodes/core/evolution/__init__.py +22 -0
- QuantNodes/core/evolution/loop.py +583 -0
- QuantNodes/core/evolution/operators.py +289 -0
- QuantNodes/core/evolution/settings.py +44 -0
- QuantNodes/core/expression.py +841 -0
- QuantNodes/core/feedback/__init__.py +38 -0
- QuantNodes/core/feedback/channels.py +182 -0
- QuantNodes/core/feedback/collector.py +91 -0
- QuantNodes/core/feedback/dataclass.py +239 -0
- QuantNodes/core/feedback/llm_judge.py +138 -0
- QuantNodes/core/knowledge/__init__.py +69 -0
- QuantNodes/core/knowledge/knowledge_base.py +217 -0
- QuantNodes/core/knowledge/lineage_compress.py +196 -0
- QuantNodes/core/knowledge/lineage_expand.py +123 -0
- QuantNodes/core/knowledge/metrics/__init__.py +43 -0
- QuantNodes/core/knowledge/metrics/evaluator.py +176 -0
- QuantNodes/core/knowledge/metrics/metrics.py +220 -0
- QuantNodes/core/knowledge/rag_prompt.py +196 -0
- QuantNodes/core/knowledge/retriever.py +209 -0
- QuantNodes/core/lambda_node.py +81 -0
- QuantNodes/core/monitoring/__init__.py +22 -0
- QuantNodes/core/monitoring/collector.py +292 -0
- QuantNodes/core/monitoring/dashboard.py +365 -0
- QuantNodes/core/node.py +375 -0
- QuantNodes/core/pandas_utils.py +504 -0
- QuantNodes/core/parallel/__init__.py +15 -0
- QuantNodes/core/parallel/worker.py +140 -0
- QuantNodes/core/parallel/worker_process.py +265 -0
- QuantNodes/core/path_utils.py +73 -0
- QuantNodes/core/pipeline.py +328 -0
- QuantNodes/core/plugin.py +135 -0
- QuantNodes/core/quality_gate/__init__.py +32 -0
- QuantNodes/core/quality_gate/complexity.py +94 -0
- QuantNodes/core/quality_gate/consistency.py +26 -0
- QuantNodes/core/quality_gate/node.py +97 -0
- QuantNodes/core/quality_gate/redundancy.py +51 -0
- QuantNodes/core/quality_gate/settings.py +43 -0
- QuantNodes/core/quality_gate/zoo.py +98 -0
- QuantNodes/core/serializable.py +116 -0
- QuantNodes/core/serialization.py +673 -0
- QuantNodes/core/tools.py +333 -0
- QuantNodes/core/trajectory/__init__.py +25 -0
- QuantNodes/core/trajectory/entry.py +116 -0
- QuantNodes/core/trajectory/lineage.py +67 -0
- QuantNodes/core/trajectory/pool.py +211 -0
- QuantNodes/core/trajectory/selector.py +140 -0
- QuantNodes/core/visualization/__init__.py +33 -0
- QuantNodes/core/visualization/builder.py +233 -0
- QuantNodes/core/visualization/gate_breakdown.py +140 -0
- QuantNodes/core/visualization/lineage_dag.py +203 -0
- QuantNodes/core/visualization/metric_distribution.py +125 -0
- QuantNodes/core/visualization/report.py +68 -0
- QuantNodes/database_node/__init__.py +69 -0
- QuantNodes/database_node/base.py +135 -0
- QuantNodes/database_node/clickhouse_node.py +272 -0
- QuantNodes/database_node/csv_node.py +83 -0
- QuantNodes/database_node/duckdb_node.py +86 -0
- QuantNodes/database_node/factory.py +83 -0
- QuantNodes/database_node/mysql_node.py +100 -0
- QuantNodes/database_node/parquet_node.py +75 -0
- QuantNodes/database_node/sqlite_node.py +67 -0
- QuantNodes/factor_node/__init__.py +50 -0
- QuantNodes/factor_node/factor.py +563 -0
- QuantNodes/factor_node/factor_db.py +421 -0
- QuantNodes/factor_node/factor_functions/__init__.py +252 -0
- QuantNodes/factor_node/factor_functions/_helpers.py +358 -0
- QuantNodes/factor_node/factor_functions/_helpers_debug.py +317 -0
- QuantNodes/factor_node/factor_functions/composite_ops.py +136 -0
- QuantNodes/factor_node/factor_functions/math_ops.py +433 -0
- QuantNodes/factor_node/factor_functions/section_ops.py +290 -0
- QuantNodes/factor_node/factor_functions/talib_ops.py +1293 -0
- QuantNodes/factor_node/factor_functions/time_ops.py +535 -0
- QuantNodes/factor_node/factor_operation.py +1115 -0
- QuantNodes/factor_node/factor_table.py +1073 -0
- QuantNodes/factor_node/quant_nodes_object.py +60 -0
- QuantNodes/mcp_server/__init__.py +27 -0
- QuantNodes/mcp_server/__main__.py +4 -0
- QuantNodes/mcp_server/server.py +272 -0
- QuantNodes/methods/__init__.py +28 -0
- QuantNodes/methods/pipeline.py +100 -0
- QuantNodes/methods/sandbox.py +102 -0
- QuantNodes/monitor/__init__.py +27 -0
- QuantNodes/monitor/agent_tools/__init__.py +5 -0
- QuantNodes/monitor/agent_tools/monitor_tool.py +98 -0
- QuantNodes/monitor/agent_tools/schedule_tool.py +98 -0
- QuantNodes/monitor/agent_tools/version_tool.py +133 -0
- QuantNodes/monitor/monitor/__init__.py +6 -0
- QuantNodes/monitor/monitor/alerter.py +60 -0
- QuantNodes/monitor/monitor/collector.py +164 -0
- QuantNodes/monitor/monitor/dashboard.py +115 -0
- QuantNodes/monitor/monitor/drift.py +190 -0
- QuantNodes/monitor/scheduler/__init__.py +4 -0
- QuantNodes/monitor/scheduler/runner.py +133 -0
- QuantNodes/monitor/scheduler/scheduler.py +184 -0
- QuantNodes/monitor/storage/__init__.py +16 -0
- QuantNodes/monitor/storage/models.py +70 -0
- QuantNodes/monitor/storage/repository.py +407 -0
- QuantNodes/monitor/version/__init__.py +4 -0
- QuantNodes/monitor/version/diff.py +81 -0
- QuantNodes/monitor/version/version_manager.py +182 -0
- QuantNodes/operator_node/__init__.py +28 -0
- QuantNodes/operator_node/base.py +97 -0
- QuantNodes/operator_node/query_node.py +129 -0
- QuantNodes/operator_node/sql_builder.py +125 -0
- QuantNodes/operator_node/sql_utils.py +172 -0
- QuantNodes/operator_node/transform.py +130 -0
- QuantNodes/operators/__init__.py +90 -0
- QuantNodes/operators/_engine.py +108 -0
- QuantNodes/operators/composite.py +161 -0
- QuantNodes/operators/composite_dag.py +667 -0
- QuantNodes/operators/composite_dag_ops.py +343 -0
- QuantNodes/operators/composite_dag_pandas_ops.py +382 -0
- QuantNodes/operators/custom.py +408 -0
- QuantNodes/operators/facade.py +164 -0
- QuantNodes/operators/math.py +163 -0
- QuantNodes/operators/proxy.py +29 -0
- QuantNodes/operators/registry.py +144 -0
- QuantNodes/operators/section.py +99 -0
- QuantNodes/operators/talib.py +757 -0
- QuantNodes/operators/templates.py +95 -0
- QuantNodes/operators/time_series.py +136 -0
- QuantNodes/prompts/__init__.py +20 -0
- QuantNodes/prompts/backtest/__init__.py +12 -0
- QuantNodes/prompts/backtest/factor_based.py +86 -0
- QuantNodes/prompts/backtest/standard.py +73 -0
- QuantNodes/prompts/factor/__init__.py +14 -0
- QuantNodes/prompts/factor/correlation.py +77 -0
- QuantNodes/prompts/factor/group_backtest.py +86 -0
- QuantNodes/prompts/factor/ic_analysis.py +91 -0
- QuantNodes/prompts/strategy/__init__.py +18 -0
- QuantNodes/prompts/strategy/market_neutral.py +96 -0
- QuantNodes/prompts/strategy/mean_reversion.py +107 -0
- QuantNodes/prompts/strategy/momentum.py +160 -0
- QuantNodes/prompts/strategy/pairs_trading.py +107 -0
- QuantNodes/prompts/strategy/trend_following.py +96 -0
- QuantNodes/research/README.md +106 -0
- QuantNodes/research/__init__.py +154 -0
- QuantNodes/research/_legacy_3c/__init__.py +61 -0
- QuantNodes/research/_legacy_3c/auto_researcher.py +289 -0
- QuantNodes/research/_legacy_3c/factor_evaluator.py +560 -0
- QuantNodes/research/_legacy_3c/factor_miner.py +318 -0
- QuantNodes/research/_legacy_3c/mcts_search.py +324 -0
- QuantNodes/research/factor_test/__init__.py +25 -0
- QuantNodes/research/factor_test/config.py +184 -0
- QuantNodes/research/factor_test/config_builder.py +276 -0
- QuantNodes/research/factor_test/e2e/data_prep.py +163 -0
- QuantNodes/research/factor_test/e2e/run_evolution_e2e.py +309 -0
- QuantNodes/research/factor_test/evolution_adapter.py +231 -0
- QuantNodes/research/factor_test/feedback_wrapper.py +102 -0
- QuantNodes/research/factor_test/ifind_db/__init__.py +7 -0
- QuantNodes/research/factor_test/ifind_db/fetcher.py +224 -0
- QuantNodes/research/factor_test/ifind_db/ifind_database.py +689 -0
- QuantNodes/research/factor_test/nodes/__init__.py +1 -0
- QuantNodes/research/factor_test/nodes/_base.py +91 -0
- QuantNodes/research/factor_test/nodes/adjust_date_node.py +48 -0
- QuantNodes/research/factor_test/nodes/configs.py +240 -0
- QuantNodes/research/factor_test/nodes/factor_neutralize_node.py +87 -0
- QuantNodes/research/factor_test/nodes/factor_preprocess_node.py +222 -0
- QuantNodes/research/factor_test/nodes/factor_score_node.py +141 -0
- QuantNodes/research/factor_test/nodes/factor_test_report_node.py +153 -0
- QuantNodes/research/factor_test/nodes/group_analyzer_node.py +317 -0
- QuantNodes/research/factor_test/nodes/ic_analyzer_node.py +112 -0
- QuantNodes/research/factor_test/nodes/load_data_node.py +100 -0
- QuantNodes/research/factor_test/nodes/long_short_node.py +93 -0
- QuantNodes/research/factor_test/nodes/neutralizers.py +222 -0
- QuantNodes/research/factor_test/nodes/preprocess_strategies.py +277 -0
- QuantNodes/research/factor_test/nodes/risk_correlation_node.py +112 -0
- QuantNodes/research/factor_test/nodes/sample_pool_filter_node.py +110 -0
- QuantNodes/research/factor_test/nodes/tradability_filter_node.py +92 -0
- QuantNodes/research/factor_test/pipeline_runner.py +305 -0
- QuantNodes/research/factor_test/pipeline_spec.py +216 -0
- QuantNodes/research/factor_test/utils/__init__.py +26 -0
- QuantNodes/research/factor_test/utils/constants.py +86 -0
- QuantNodes/research/factor_test/utils/data_loader.py +141 -0
- QuantNodes/research/factor_test/utils/date_utils.py +232 -0
- QuantNodes/research/factor_test/utils/file_loaders.py +150 -0
- QuantNodes/research/factor_test/utils/labels.py +37 -0
- QuantNodes/research/factor_test/utils/metrics_extractor.py +55 -0
- QuantNodes/research/factor_test/utils/performance_metrics.py +175 -0
- QuantNodes/research/factor_test/utils/safe_load.py +106 -0
- QuantNodes/research/quant_alpha/CHANGELOG.md +80 -0
- QuantNodes/research/quant_alpha/README.md +142 -0
- QuantNodes/research/quant_alpha/__init__.py +45 -0
- QuantNodes/research/quant_alpha/adapters/__init__.py +99 -0
- QuantNodes/research/quant_alpha/adapters/calculator.py +503 -0
- QuantNodes/research/quant_alpha/adapters/expression.py +387 -0
- QuantNodes/research/quant_alpha/alpha101_design/__init__.py +50 -0
- QuantNodes/research/quant_alpha/alpha101_design/few_shot_examples.py +243 -0
- QuantNodes/research/quant_alpha/alpha101_design/philosophy.py +474 -0
- QuantNodes/research/quant_alpha/alpha158_design/__init__.py +63 -0
- QuantNodes/research/quant_alpha/alpha158_design/few_shot_examples.py +219 -0
- QuantNodes/research/quant_alpha/alpha158_design/philosophy.py +240 -0
- QuantNodes/research/quant_alpha/evaluation/__init__.py +47 -0
- QuantNodes/research/quant_alpha/evaluation/baselines/__init__.py +8 -0
- QuantNodes/research/quant_alpha/evaluation/baselines/g1_handcrafted.py +135 -0
- QuantNodes/research/quant_alpha/evaluation/baselines/g2_llm_only.py +269 -0
- QuantNodes/research/quant_alpha/evaluation/baselines/g3_alpha_gpt.py +152 -0
- QuantNodes/research/quant_alpha/evaluation/clickhouse_data_loader.py +227 -0
- QuantNodes/research/quant_alpha/evaluation/contracts.py +376 -0
- QuantNodes/research/quant_alpha/evaluation/evaluators/__init__.py +6 -0
- QuantNodes/research/quant_alpha/evaluation/evaluators/polars_evaluator.py +545 -0
- QuantNodes/research/quant_alpha/evaluation/mock_data_loader.py +226 -0
- QuantNodes/research/quant_alpha/evaluation/runner.py +243 -0
- QuantNodes/research/quant_alpha/llm/__init__.py +38 -0
- QuantNodes/research/quant_alpha/llm/parser.py +681 -0
- QuantNodes/research/quant_alpha/logic_driven_pipeline.py +411 -0
- QuantNodes/research/quant_alpha/logic_mining/__init__.py +74 -0
- QuantNodes/research/quant_alpha/logic_mining/compiler.py +457 -0
- QuantNodes/research/quant_alpha/logic_mining/generator.py +366 -0
- QuantNodes/research/quant_alpha/logic_mining/models.py +252 -0
- QuantNodes/research/quant_alpha/logic_mining/parser.py +287 -0
- QuantNodes/research/quant_alpha/logic_mining/pipelines.py +297 -0
- QuantNodes/research/quant_alpha/logic_mining/sources.py +149 -0
- QuantNodes/research/quant_alpha/mcts/__init__.py +66 -0
- QuantNodes/research/quant_alpha/mcts/cache.py +262 -0
- QuantNodes/research/quant_alpha/mcts/extension_ops.py +320 -0
- QuantNodes/research/quant_alpha/mcts/feedback.py +825 -0
- QuantNodes/research/quant_alpha/mcts/op_prior.py +180 -0
- QuantNodes/research/quant_alpha/mcts/search.py +540 -0
- QuantNodes/research/quant_alpha/mcts/tree.py +201 -0
- QuantNodes/research/quant_alpha/operator_vocab/__init__.py +50 -0
- QuantNodes/research/quant_alpha/operator_vocab/config.py +54 -0
- QuantNodes/research/quant_alpha/operator_vocab/metadata.py +263 -0
- QuantNodes/research/quant_alpha/operator_vocab/vocabulary.py +481 -0
- QuantNodes/research/quant_alpha/pipeline.py +1027 -0
- QuantNodes/research/quant_alpha/types/__init__.py +27 -0
- QuantNodes/research/quant_alpha/types/constants.py +28 -0
- QuantNodes/research/quant_alpha/types/state.py +205 -0
- QuantNodes/research/quant_alpha/workflow/__init__.py +32 -0
- QuantNodes/research/quant_alpha/workflow/alpha_gpt.py +911 -0
- QuantNodes/research/quant_alpha/workflow/alpha_logics.py +416 -0
- QuantNodes/research/quant_alpha/workflow/state.py +27 -0
- QuantNodes/research/report_reproducer.py +485 -0
- QuantNodes/research/wiki.py +1155 -0
- QuantNodes/symbolic/__init__.py +51 -0
- QuantNodes/symbolic/compiler.py +113 -0
- QuantNodes/symbolic/dialect.py +260 -0
- QuantNodes/symbolic/executor.py +147 -0
- QuantNodes/symbolic/expression.py +234 -0
- QuantNodes/symbolic/functions.py +433 -0
- QuantNodes/symbolic/optimizer.py +165 -0
- QuantNodes/ui_node/__init__.py +30 -0
- QuantNodes/ui_node/base.py +222 -0
- quantnodes-3.0.0.dist-info/METADATA +463 -0
- quantnodes-3.0.0.dist-info/RECORD +399 -0
- quantnodes-3.0.0.dist-info/WHEEL +5 -0
- quantnodes-3.0.0.dist-info/entry_points.txt +24 -0
- quantnodes-3.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
"""
|
|
3
|
+
operators.custom - 用户友好自定义算子 API
|
|
4
|
+
|
|
5
|
+
提供装饰器风格和 Builder 风格的算子定义接口。
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import inspect
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from typing import Any, Callable, Dict, List, Optional, Union
|
|
13
|
+
|
|
14
|
+
from polars import Expr
|
|
15
|
+
|
|
16
|
+
from QuantNodes.operators.registry import _CustomOperatorRegistry
|
|
17
|
+
from QuantNodes.operators.templates import OperatorTemplate
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class CustomOperatorBuilder:
|
|
21
|
+
"""链式构建器"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, name: str, category: str):
|
|
24
|
+
self._name = name
|
|
25
|
+
self._category = category
|
|
26
|
+
self._params: Dict[str, dict] = {}
|
|
27
|
+
self._func: Optional[Callable] = None
|
|
28
|
+
self._doc: str = ""
|
|
29
|
+
self._aliases: List[str] = []
|
|
30
|
+
self._decorator_mode: bool = False
|
|
31
|
+
|
|
32
|
+
def param(
|
|
33
|
+
self, name: str, type_: Any = None, default: Any = None, desc: str = ""
|
|
34
|
+
) -> "CustomOperatorBuilder":
|
|
35
|
+
"""声明参数"""
|
|
36
|
+
self._params[name] = {"type": type_, "default": default, "desc": desc}
|
|
37
|
+
return self
|
|
38
|
+
|
|
39
|
+
def execute(self, func: Callable) -> "CustomOperatorBuilder":
|
|
40
|
+
"""设置执行函数"""
|
|
41
|
+
self._func = func
|
|
42
|
+
return self
|
|
43
|
+
|
|
44
|
+
def doc(self, docstring: str) -> "CustomOperatorBuilder":
|
|
45
|
+
"""设置文档"""
|
|
46
|
+
self._doc = docstring
|
|
47
|
+
return self
|
|
48
|
+
|
|
49
|
+
def alias(self, name: str) -> "CustomOperatorBuilder":
|
|
50
|
+
"""添加别名"""
|
|
51
|
+
self._aliases.append(name)
|
|
52
|
+
return self
|
|
53
|
+
|
|
54
|
+
def register(self) -> Callable:
|
|
55
|
+
"""注册并返回被装饰的函数"""
|
|
56
|
+
if self._func is None:
|
|
57
|
+
raise ValueError("execute() must be called before register()")
|
|
58
|
+
|
|
59
|
+
return self._do_register(self._func)
|
|
60
|
+
|
|
61
|
+
def _do_register(self, func: Callable) -> Callable:
|
|
62
|
+
"""执行注册逻辑"""
|
|
63
|
+
if self._func is None:
|
|
64
|
+
self._func = func
|
|
65
|
+
|
|
66
|
+
sig = inspect.signature(self._func)
|
|
67
|
+
|
|
68
|
+
if not self._doc:
|
|
69
|
+
params_parts = []
|
|
70
|
+
for n, v in self._params.items():
|
|
71
|
+
if v["default"] is not None:
|
|
72
|
+
params_parts.append(f"{n}={v['default']!r}")
|
|
73
|
+
else:
|
|
74
|
+
params_parts.append(n)
|
|
75
|
+
params_str = ", ".join(params_parts)
|
|
76
|
+
self._doc = f"{self._name}({params_str})"
|
|
77
|
+
|
|
78
|
+
original_func = self._func
|
|
79
|
+
|
|
80
|
+
def wrapper(f: Union[Expr, str], **kwargs) -> Expr:
|
|
81
|
+
args = [f]
|
|
82
|
+
for param_name, param_info in self._params.items():
|
|
83
|
+
if param_name not in kwargs and param_info["default"] is not None:
|
|
84
|
+
kwargs[param_name] = param_info["default"]
|
|
85
|
+
bound = sig.bind(*args, **kwargs)
|
|
86
|
+
return original_func(*bound.args, **bound.kwargs)
|
|
87
|
+
|
|
88
|
+
wrapper.__name__ = self._name
|
|
89
|
+
wrapper.__qualname__ = f"CustomOperator.{self._name}"
|
|
90
|
+
wrapper.__doc__ = self._doc
|
|
91
|
+
|
|
92
|
+
_CustomOperatorRegistry.register(
|
|
93
|
+
self._category,
|
|
94
|
+
self._name,
|
|
95
|
+
wrapper,
|
|
96
|
+
self._doc,
|
|
97
|
+
self._params,
|
|
98
|
+
self._aliases,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
for alias in self._aliases:
|
|
102
|
+
_CustomOperatorRegistry.register_alias(alias, self._name, self._category)
|
|
103
|
+
|
|
104
|
+
return wrapper
|
|
105
|
+
|
|
106
|
+
def __call__(self, func: Callable) -> Callable:
|
|
107
|
+
"""当作为装饰器使用时直接注册"""
|
|
108
|
+
return self._do_register(func)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class CustomOperator:
|
|
112
|
+
"""自定义算子工厂(类方法集合)"""
|
|
113
|
+
|
|
114
|
+
@classmethod
|
|
115
|
+
def point(cls, name: str) -> CustomOperatorBuilder:
|
|
116
|
+
"""创建 point 算子构建器"""
|
|
117
|
+
return CustomOperatorBuilder(name, "point")
|
|
118
|
+
|
|
119
|
+
@classmethod
|
|
120
|
+
def time(cls, name: str) -> CustomOperatorBuilder:
|
|
121
|
+
"""创建 time 算子构建器"""
|
|
122
|
+
return CustomOperatorBuilder(name, "time")
|
|
123
|
+
|
|
124
|
+
@classmethod
|
|
125
|
+
def section(cls, name: str) -> CustomOperatorBuilder:
|
|
126
|
+
"""创建 section 算子构建器"""
|
|
127
|
+
return CustomOperatorBuilder(name, "section")
|
|
128
|
+
|
|
129
|
+
@classmethod
|
|
130
|
+
def multi_section(cls, name: str) -> CustomOperatorBuilder:
|
|
131
|
+
"""创建 multi_section 算子构建器"""
|
|
132
|
+
return CustomOperatorBuilder(name, "multi_section")
|
|
133
|
+
|
|
134
|
+
@classmethod
|
|
135
|
+
def talib(cls, name: str) -> CustomOperatorBuilder:
|
|
136
|
+
"""创建 talib 算子构建器"""
|
|
137
|
+
return CustomOperatorBuilder(name, "talib")
|
|
138
|
+
|
|
139
|
+
@classmethod
|
|
140
|
+
def from_template(
|
|
141
|
+
cls, name: str, template: str, category: str = None, **defaults
|
|
142
|
+
) -> OperatorTemplate:
|
|
143
|
+
"""基于模板创建算子"""
|
|
144
|
+
return OperatorTemplate(name, category or "time", template, defaults)
|
|
145
|
+
|
|
146
|
+
@classmethod
|
|
147
|
+
def time_from(cls, name: str, template: str, **defaults) -> OperatorTemplate:
|
|
148
|
+
"""基于 time 模板创建算子"""
|
|
149
|
+
return OperatorTemplate(name, "time", template, defaults)
|
|
150
|
+
|
|
151
|
+
@classmethod
|
|
152
|
+
def section_from(
|
|
153
|
+
cls, name: str, template: str, **defaults
|
|
154
|
+
) -> OperatorTemplate:
|
|
155
|
+
"""基于 section 模板创建算子"""
|
|
156
|
+
return OperatorTemplate(name, "section", template, defaults)
|
|
157
|
+
|
|
158
|
+
@classmethod
|
|
159
|
+
def point_from(
|
|
160
|
+
cls, name: str, template: str, **defaults
|
|
161
|
+
) -> OperatorTemplate:
|
|
162
|
+
"""基于 point 模板创建算子"""
|
|
163
|
+
return OperatorTemplate(name, "point", template, defaults)
|
|
164
|
+
|
|
165
|
+
@classmethod
|
|
166
|
+
def list(
|
|
167
|
+
cls, category: Optional[str] = None, include_builtin: bool = False
|
|
168
|
+
) -> List[str]:
|
|
169
|
+
"""列出算子"""
|
|
170
|
+
custom = _CustomOperatorRegistry.list(category)
|
|
171
|
+
if not include_builtin:
|
|
172
|
+
return custom
|
|
173
|
+
from QuantNodes.factor_node.factor_functions import list_operators
|
|
174
|
+
|
|
175
|
+
builtin = list_operators(category)
|
|
176
|
+
seen = set()
|
|
177
|
+
result = []
|
|
178
|
+
for name in custom + builtin:
|
|
179
|
+
if name not in seen:
|
|
180
|
+
seen.add(name)
|
|
181
|
+
result.append(name)
|
|
182
|
+
return result
|
|
183
|
+
|
|
184
|
+
@classmethod
|
|
185
|
+
def get(cls, name: str) -> Optional[Callable]:
|
|
186
|
+
"""获取算子函数(先查自定义,再查内置)"""
|
|
187
|
+
func = _CustomOperatorRegistry.get(name)
|
|
188
|
+
if func:
|
|
189
|
+
return func
|
|
190
|
+
from QuantNodes.factor_node.factor_functions import get_operator
|
|
191
|
+
|
|
192
|
+
return get_operator(name)
|
|
193
|
+
|
|
194
|
+
@classmethod
|
|
195
|
+
def info(cls, name: str) -> Optional[Dict[str, Any]]:
|
|
196
|
+
"""获取算子详细信息"""
|
|
197
|
+
info = _CustomOperatorRegistry.info(name)
|
|
198
|
+
if info:
|
|
199
|
+
return info
|
|
200
|
+
from QuantNodes.factor_node.factor_functions import operator_info
|
|
201
|
+
|
|
202
|
+
return operator_info(name)
|
|
203
|
+
|
|
204
|
+
@classmethod
|
|
205
|
+
def unregister(cls, name: str) -> bool:
|
|
206
|
+
"""注销自定义算子"""
|
|
207
|
+
return _CustomOperatorRegistry.unregister(name)
|
|
208
|
+
|
|
209
|
+
@classmethod
|
|
210
|
+
def unregister_all(cls) -> int:
|
|
211
|
+
"""注销所有自定义算子"""
|
|
212
|
+
return _CustomOperatorRegistry.unregister_all()
|
|
213
|
+
|
|
214
|
+
@classmethod
|
|
215
|
+
def register(
|
|
216
|
+
cls, category: str, name: str, func: Callable, **kwargs
|
|
217
|
+
) -> Callable:
|
|
218
|
+
"""
|
|
219
|
+
直接注册自定义算子的便捷方法
|
|
220
|
+
|
|
221
|
+
Args:
|
|
222
|
+
category: 算子类别 ("point", "time", "section", "multi_section", "talib")
|
|
223
|
+
name: 算子名称
|
|
224
|
+
func: 算子函数
|
|
225
|
+
**kwargs: 额外参数
|
|
226
|
+
|
|
227
|
+
Returns:
|
|
228
|
+
注册后的函数
|
|
229
|
+
|
|
230
|
+
Example:
|
|
231
|
+
>>> def my_double(f, multiplier=2.0):
|
|
232
|
+
... return f * multiplier
|
|
233
|
+
>>> CustomOperator.register("point", "my_double", my_double)
|
|
234
|
+
"""
|
|
235
|
+
_CustomOperatorRegistry.register(category, name, func, **kwargs)
|
|
236
|
+
return func
|
|
237
|
+
|
|
238
|
+
@classmethod
|
|
239
|
+
def count(cls) -> int:
|
|
240
|
+
"""返回自定义算子数量"""
|
|
241
|
+
return _CustomOperatorRegistry.count()
|
|
242
|
+
|
|
243
|
+
@classmethod
|
|
244
|
+
def export(cls, path: str, format: str = "yaml") -> None:
|
|
245
|
+
"""导出到 YAML/JSON"""
|
|
246
|
+
data = {
|
|
247
|
+
"version": 1,
|
|
248
|
+
"exported_at": datetime.now().isoformat(),
|
|
249
|
+
"operators": [],
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
for cat in _CustomOperatorRegistry._registry:
|
|
253
|
+
for name, info in _CustomOperatorRegistry._registry[cat].items():
|
|
254
|
+
op_data = {
|
|
255
|
+
"name": name,
|
|
256
|
+
"category": cat,
|
|
257
|
+
"doc": info.get("doc", ""),
|
|
258
|
+
"source": info.get("source", ""),
|
|
259
|
+
}
|
|
260
|
+
params = info.get("params", {})
|
|
261
|
+
if params:
|
|
262
|
+
op_data["params"] = params
|
|
263
|
+
data["operators"].append(op_data)
|
|
264
|
+
|
|
265
|
+
if format == "yaml":
|
|
266
|
+
import yaml
|
|
267
|
+
|
|
268
|
+
with open(path, "w", encoding="utf-8") as f:
|
|
269
|
+
yaml.dump(data, f, allow_unicode=True, sort_keys=False)
|
|
270
|
+
else:
|
|
271
|
+
import json
|
|
272
|
+
|
|
273
|
+
with open(path, "w", encoding="utf-8") as f:
|
|
274
|
+
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
275
|
+
|
|
276
|
+
@classmethod
|
|
277
|
+
def import_(cls, path: str) -> int:
|
|
278
|
+
"""从 YAML/JSON 导入,返回导入数量"""
|
|
279
|
+
import yaml
|
|
280
|
+
|
|
281
|
+
with open(path, encoding="utf-8") as f:
|
|
282
|
+
data = yaml.safe_load(f)
|
|
283
|
+
|
|
284
|
+
count = 0
|
|
285
|
+
for op in data.get("operators", []):
|
|
286
|
+
source = op.get("source", "")
|
|
287
|
+
if source:
|
|
288
|
+
namespace = {}
|
|
289
|
+
exec(source, namespace)
|
|
290
|
+
func = namespace.get(op["name"])
|
|
291
|
+
if func:
|
|
292
|
+
_CustomOperatorRegistry.register(
|
|
293
|
+
op["category"],
|
|
294
|
+
op["name"],
|
|
295
|
+
func,
|
|
296
|
+
op.get("doc", ""),
|
|
297
|
+
op.get("params", {}),
|
|
298
|
+
)
|
|
299
|
+
count += 1
|
|
300
|
+
return count
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def _make_decorator(category: str):
|
|
304
|
+
"""创建分类装饰器"""
|
|
305
|
+
|
|
306
|
+
def decorator(name: str):
|
|
307
|
+
def wrapper(func: Callable) -> Callable:
|
|
308
|
+
_CustomOperatorRegistry.register(
|
|
309
|
+
category,
|
|
310
|
+
name,
|
|
311
|
+
func,
|
|
312
|
+
inspect.getdoc(func) or "",
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
def _wrapper(f: Union[Expr, str], **kwargs) -> Expr:
|
|
316
|
+
return func(f, **kwargs)
|
|
317
|
+
|
|
318
|
+
_wrapper.__name__ = func.__name__
|
|
319
|
+
_wrapper.__doc__ = func.__doc__
|
|
320
|
+
return _wrapper
|
|
321
|
+
|
|
322
|
+
return decorator(name) if callable(name) else lambda f: decorator(name)(f)
|
|
323
|
+
|
|
324
|
+
return decorator
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def _register_point(name: str) -> Callable:
|
|
328
|
+
"""point 算子装饰器"""
|
|
329
|
+
|
|
330
|
+
def decorator(func: Callable) -> Callable:
|
|
331
|
+
_CustomOperatorRegistry.register(
|
|
332
|
+
"point",
|
|
333
|
+
name,
|
|
334
|
+
func,
|
|
335
|
+
inspect.getdoc(func) or "",
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
def _wrapper(f: Union[Expr, str], **kwargs) -> Expr:
|
|
339
|
+
return func(f, **kwargs)
|
|
340
|
+
|
|
341
|
+
_wrapper.__name__ = func.__name__
|
|
342
|
+
_wrapper.__doc__ = func.__doc__
|
|
343
|
+
return _wrapper
|
|
344
|
+
|
|
345
|
+
return decorator
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def point(name: str) -> Callable:
|
|
349
|
+
"""point 算子装饰器"""
|
|
350
|
+
|
|
351
|
+
def decorator(func: Callable) -> Callable:
|
|
352
|
+
_CustomOperatorRegistry.register(
|
|
353
|
+
"point",
|
|
354
|
+
name,
|
|
355
|
+
func,
|
|
356
|
+
inspect.getdoc(func) or "",
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
def _wrapper(f: Union[Expr, str], **kwargs) -> Expr:
|
|
360
|
+
return func(f, **kwargs)
|
|
361
|
+
|
|
362
|
+
_wrapper.__name__ = func.__name__
|
|
363
|
+
_wrapper.__doc__ = func.__doc__
|
|
364
|
+
return _wrapper
|
|
365
|
+
|
|
366
|
+
return decorator
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def time(name: str) -> Callable:
|
|
370
|
+
"""time 算子装饰器"""
|
|
371
|
+
|
|
372
|
+
def decorator(func: Callable) -> Callable:
|
|
373
|
+
_CustomOperatorRegistry.register(
|
|
374
|
+
"time",
|
|
375
|
+
name,
|
|
376
|
+
func,
|
|
377
|
+
inspect.getdoc(func) or "",
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
def _wrapper(f: Union[Expr, str], **kwargs) -> Expr:
|
|
381
|
+
return func(f, **kwargs)
|
|
382
|
+
|
|
383
|
+
_wrapper.__name__ = func.__name__
|
|
384
|
+
_wrapper.__doc__ = func.__doc__
|
|
385
|
+
return _wrapper
|
|
386
|
+
|
|
387
|
+
return decorator
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
def section(name: str) -> Callable:
|
|
391
|
+
"""section 算子装饰器"""
|
|
392
|
+
|
|
393
|
+
def decorator(func: Callable) -> Callable:
|
|
394
|
+
_CustomOperatorRegistry.register(
|
|
395
|
+
"section",
|
|
396
|
+
name,
|
|
397
|
+
func,
|
|
398
|
+
inspect.getdoc(func) or "",
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
def _wrapper(f: Union[Expr, str], **kwargs) -> Expr:
|
|
402
|
+
return func(f, **kwargs)
|
|
403
|
+
|
|
404
|
+
_wrapper.__name__ = func.__name__
|
|
405
|
+
_wrapper.__doc__ = func.__doc__
|
|
406
|
+
return _wrapper
|
|
407
|
+
|
|
408
|
+
return decorator
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
"""
|
|
3
|
+
operators.facade - 算子统一查询门面 (Facade, Phase 3.2, 2026-06-22)
|
|
4
|
+
|
|
5
|
+
QuantNodes 有 3 个并列的算子注册表 (docs/26 §3.3):
|
|
6
|
+
|
|
7
|
+
L0 内置 (_OPERATOR_REGISTRY) factor_node/factor_functions
|
|
8
|
+
L1 复合 DAG (_COMPOSITE_REGISTRY) operators/composite_dag.py
|
|
9
|
+
L2 自定义 (_CustomOperatorRegistry) operators/registry.py
|
|
10
|
+
|
|
11
|
+
调用方 (agent/config/executor.py, loader.py) 此前需分别 import:
|
|
12
|
+
- get_operator / list_operators / operator_info (L0, 内部已级联 L2)
|
|
13
|
+
- is_composite_op / get_composite_spec / list_composite_ops (L1, 完全隔离)
|
|
14
|
+
- CustomOperator.get / _CustomOperatorRegistry.list (L2)
|
|
15
|
+
|
|
16
|
+
本 Facade 提供**单一只读入口**统一这 3 层查询, 调用方只需:
|
|
17
|
+
|
|
18
|
+
from QuantNodes.operators import operator_facade as ops
|
|
19
|
+
fn = ops.resolve("ts_mean") # L0/L2 callable
|
|
20
|
+
spec = ops.get_composite(name) # L1 CompositeSpec
|
|
21
|
+
if ops.exists(name): ...
|
|
22
|
+
ops.kind(name) # -> "custom" / "builtin" / "composite" / None
|
|
23
|
+
ops.list_all() # 三层去重合并
|
|
24
|
+
|
|
25
|
+
设计要点 (Facade 模式):
|
|
26
|
+
- **只委托, 不改行为**: 全部转调既有函数, 与旧 API bitwise 一致 (向后兼容)。
|
|
27
|
+
- **只读**: 注册仍走各自的 @register_operator / @composite_operator /
|
|
28
|
+
CustomOperator (写路径不收敛, 避免破坏隔离语义)。
|
|
29
|
+
- L0 的 ``get_operator`` 本身已级联 L2 (custom→builtin), Facade 借此保持
|
|
30
|
+
与旧查询完全一致的优先级; L1 因严格隔离 (见 composite_dag.py:137-146)
|
|
31
|
+
单独暴露 ``get_composite`` / ``is_composite``。
|
|
32
|
+
"""
|
|
33
|
+
from __future__ import annotations
|
|
34
|
+
|
|
35
|
+
from typing import Any, Callable, Dict, List, Optional, TYPE_CHECKING
|
|
36
|
+
|
|
37
|
+
if TYPE_CHECKING:
|
|
38
|
+
from QuantNodes.operators.composite_dag import CompositeSpec
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class OperatorFacade:
|
|
42
|
+
"""3 层算子注册表的统一只读门面.
|
|
43
|
+
|
|
44
|
+
所有方法均委托给既有查询函数, 不缓存、不持有状态, 因此对运行时新增的
|
|
45
|
+
算子注册 (custom / composite) 实时可见。
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
# ---- L0 + L2 (callable 级联查询) ----
|
|
49
|
+
|
|
50
|
+
def resolve(self, name: str, category: Optional[str] = None) -> Optional[Callable]:
|
|
51
|
+
"""获取算子 callable (级联: 自定义 L2 → 内置 L0)。
|
|
52
|
+
|
|
53
|
+
与 ``factor_functions.get_operator`` 行为完全一致。composite (L1) 不在
|
|
54
|
+
此返回 (它们不是直接 callable), 请用 :meth:`get_composite`。
|
|
55
|
+
"""
|
|
56
|
+
from QuantNodes.factor_node.factor_functions import get_operator
|
|
57
|
+
|
|
58
|
+
return get_operator(name, category)
|
|
59
|
+
|
|
60
|
+
def info(self, name: str, category: Optional[str] = None) -> Optional[Dict[str, Any]]:
|
|
61
|
+
"""获取算子详细信息 dict (级联: L2 → L0)。"""
|
|
62
|
+
from QuantNodes.factor_node.factor_functions import operator_info
|
|
63
|
+
|
|
64
|
+
return operator_info(name, category)
|
|
65
|
+
|
|
66
|
+
# ---- L1 (composite, 隔离查询) ----
|
|
67
|
+
|
|
68
|
+
def get_composite(self, name: str, engine: str = "any") -> Optional["CompositeSpec"]:
|
|
69
|
+
"""获取 composite DAG 的 ``CompositeSpec`` (L1, 与 L0/L2 隔离)。
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
name: 算子名
|
|
73
|
+
engine: "any" (default) | "polars" | "pandas"
|
|
74
|
+
"""
|
|
75
|
+
from QuantNodes.operators.composite_dag import get_composite_spec
|
|
76
|
+
|
|
77
|
+
return get_composite_spec(name, engine=engine)
|
|
78
|
+
|
|
79
|
+
def is_composite(self, name: str, engine: str = "any") -> bool:
|
|
80
|
+
"""判断 name 是否是 composite 算子 (L1)。
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
name: 算子名
|
|
84
|
+
engine: "any" (default) | "polars" | "pandas"
|
|
85
|
+
"""
|
|
86
|
+
from QuantNodes.operators.composite_dag import is_composite_op
|
|
87
|
+
|
|
88
|
+
return is_composite_op(name, engine=engine)
|
|
89
|
+
|
|
90
|
+
# ---- 跨层统一查询 ----
|
|
91
|
+
|
|
92
|
+
def exists(self, name: str) -> bool:
|
|
93
|
+
"""name 是否在任一层注册 (callable 或 composite)。"""
|
|
94
|
+
if self.is_composite(name):
|
|
95
|
+
return True
|
|
96
|
+
return self.resolve(name) is not None
|
|
97
|
+
|
|
98
|
+
def kind(self, name: str) -> Optional[str]:
|
|
99
|
+
"""返回 name 所属层: ``"custom"`` / ``"builtin"`` / ``"composite"`` / ``None``.
|
|
100
|
+
|
|
101
|
+
优先级与查询级联一致 (custom → builtin → composite)。同名时返回最先
|
|
102
|
+
命中的层 (与 :meth:`resolve` 实际返回的实现保持一致)。
|
|
103
|
+
"""
|
|
104
|
+
from QuantNodes.operators.registry import _CustomOperatorRegistry
|
|
105
|
+
|
|
106
|
+
if _CustomOperatorRegistry.get(name) is not None:
|
|
107
|
+
return "custom"
|
|
108
|
+
if self.resolve(name) is not None:
|
|
109
|
+
return "builtin"
|
|
110
|
+
if self.is_composite(name):
|
|
111
|
+
return "composite"
|
|
112
|
+
return None
|
|
113
|
+
|
|
114
|
+
def list_all(
|
|
115
|
+
self,
|
|
116
|
+
category: Optional[str] = None,
|
|
117
|
+
include_custom: bool = True,
|
|
118
|
+
include_composite: bool = True,
|
|
119
|
+
) -> List[str]:
|
|
120
|
+
"""列出三层算子名 (去重, 保持 custom → builtin → composite 顺序)。
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
category: 限定类别 (point/time/section/multi_section/talib)。
|
|
124
|
+
include_custom: 是否含 L2 自定义 (默认 True)。
|
|
125
|
+
include_composite: 是否含 L1 composite (默认 True)。
|
|
126
|
+
"""
|
|
127
|
+
from QuantNodes.factor_node.factor_functions import list_operators
|
|
128
|
+
|
|
129
|
+
# list_operators 已做 custom(L2) + builtin(L0) 去重合并
|
|
130
|
+
names = list(list_operators(category=category, include_custom=include_custom))
|
|
131
|
+
|
|
132
|
+
if include_composite:
|
|
133
|
+
from QuantNodes.operators.composite_dag import list_composite_ops
|
|
134
|
+
|
|
135
|
+
seen = set(names)
|
|
136
|
+
for name in list_composite_ops(category=category):
|
|
137
|
+
if name not in seen:
|
|
138
|
+
seen.add(name)
|
|
139
|
+
names.append(name)
|
|
140
|
+
return names
|
|
141
|
+
|
|
142
|
+
def documentation(
|
|
143
|
+
self, output_format: str = "markdown", category: Optional[str] = None
|
|
144
|
+
) -> str:
|
|
145
|
+
"""生成 L0 内置算子文档 (委托 ``generate_documentation``)。
|
|
146
|
+
|
|
147
|
+
composite (L1) 的 LLM 文档另有专用入口 :meth:`composite_doc_for_llm`。
|
|
148
|
+
"""
|
|
149
|
+
from QuantNodes.factor_node.factor_functions import generate_documentation
|
|
150
|
+
|
|
151
|
+
return generate_documentation(output_format=output_format, category=category)
|
|
152
|
+
|
|
153
|
+
def composite_doc_for_llm(self) -> str:
|
|
154
|
+
"""生成 composite (L1) 给 LLM 的 markdown 文档。"""
|
|
155
|
+
from QuantNodes.operators.composite_dag import get_composite_doc_for_llm
|
|
156
|
+
|
|
157
|
+
return get_composite_doc_for_llm()
|
|
158
|
+
|
|
159
|
+
def __repr__(self) -> str:
|
|
160
|
+
return "<OperatorFacade L0+L1+L2 unified read-only>"
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
# 模块级单例 — 调用方统一从这里查询
|
|
164
|
+
operator_facade = OperatorFacade()
|