programgarden-core 2.6.1__tar.gz → 2.6.3__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.
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/PKG-INFO +6 -4
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/README.md +5 -3
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/__init__.py +2 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/i18n/locales/en.json +37 -6
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/i18n/locales/ko.json +37 -6
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/__init__.py +4 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/backtest_futures.py +34 -24
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/base.py +66 -0
- programgarden_core-2.6.3/programgarden_core/nodes/ranking_korea_stock.py +277 -0
- programgarden_core-2.6.3/programgarden_core/nodes/ranking_stock.py +248 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/registry/node_registry.py +2 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/pyproject.toml +1 -1
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/bases/__init__.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/bases/client.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/bases/components.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/bases/listener.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/bases/mixins.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/bases/products.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/bases/sql.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/bases/storage.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/code_node.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/exceptions.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/expression/__init__.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/expression/evaluator.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/expression/reference.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/i18n/__init__.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/i18n/translator.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/korea_alias.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/market_calendar.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/models/__init__.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/models/connection_rule.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/models/credential.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/models/edge.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/models/event.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/models/exchange.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/models/field_binding.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/models/job.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/models/order_diagnostics.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/models/plugin_resource.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/models/resilience.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/models/resource.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/models/validation.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/models/workflow.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/account_futures.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/account_korea_stock.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/account_stock.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/ai.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/backtest.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/backtest_korea_stock.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/backtest_stock.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/broker.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/calculation.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/code.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/condition.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/contract_info_futures.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/data.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/data_futures.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/data_korea_stock.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/data_stock.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/display.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/event.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/fundamental_korea_stock.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/fundamental_stock.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/infra.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/open_orders_futures.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/open_orders_korea_stock.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/open_orders_stock.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/order.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/orderable_quantity_futures.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/portfolio.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/realtime_futures.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/realtime_korea_stock.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/realtime_stock.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/risk.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/session_gate.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/symbol.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/symbol_futures.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/symbol_korea_stock.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/symbol_stock.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/trigger.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/presets/__init__.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/presets/news_analyst.json +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/presets/risk_manager.json +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/presets/strategist.json +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/presets/technical_analyst.json +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/registry/__init__.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/registry/credential_registry.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/registry/plugin_registry.py +0 -0
- {programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/retry_executor.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: programgarden-core
|
|
3
|
-
Version: 2.6.
|
|
3
|
+
Version: 2.6.3
|
|
4
4
|
Summary: ProgramGarden Core - 노드 기반 DSL 핵심 타입 정의
|
|
5
5
|
License-Expression: AGPL-3.0-or-later
|
|
6
6
|
Author: 프로그램동산
|
|
@@ -15,6 +15,8 @@ Requires-Dist: pydantic (>=2.0.1,<3.0.0)
|
|
|
15
15
|
Requires-Dist: tzdata (>=2025.2,<2026.0)
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
17
|
|
|
18
|
+
The 2.6.2 release candidate [futures minute alias correction](../../docs/futures-minute-alias-contract.md) aligns canonical minute periods with the existing one-page o3103 path and rejects unsupported hourly/adjustment claims. Complete-range coverage and consumer adoption are not implied.
|
|
19
|
+
|
|
18
20
|
US regular-session requests can opt into SessionGateNode.exchange_calendar (XNYS/XNAS) for scheduled holidays and early closes. See [session gates](../../docs/session-gates-and-guarded-split.md).
|
|
19
21
|
|
|
20
22
|
# ProgramGarden Core
|
|
@@ -58,13 +60,13 @@ poetry add programgarden-core
|
|
|
58
60
|
|
|
59
61
|
요구 사항: Python 3.12+
|
|
60
62
|
|
|
61
|
-
## Node categories (11 categories,
|
|
63
|
+
## Node categories (11 categories, 74 core nodes)
|
|
62
64
|
|
|
63
65
|
| 카테고리 | 노드 수 | 대표 노드 |
|
|
64
66
|
|----------|---------|----------|
|
|
65
67
|
| infra | 8 | StartNode, BrokerNode, ThrottleNode, SplitNode, AggregateNode, IfNode, KoreaStockBrokerNode |
|
|
66
68
|
| account | 13 | AccountNode, OpenOrdersNode, RealAccountNode, RealOrderEventNode (해외주식/선물 + 국내주식) |
|
|
67
|
-
| market |
|
|
69
|
+
| market | 23 | MarketDataNode, HistoricalDataNode, RealMarketDataNode, WatchlistNode, ExclusionListNode, KoreaStockRankingNode, OverseasStockRankingNode, KoreaStock* |
|
|
68
70
|
| condition | 2 | ConditionNode, LogicNode |
|
|
69
71
|
| order | 10 | NewOrderNode, ModifyOrderNode, CancelOrderNode, PositionSizingNode (해외주식/선물 + 국내주식) |
|
|
70
72
|
| risk | 1 | PortfolioNode |
|
|
@@ -74,7 +76,7 @@ poetry add programgarden-core
|
|
|
74
76
|
| analysis | 2 | BacktestEngineNode, BenchmarkCompareNode |
|
|
75
77
|
| ai | 2 | LLMModelNode, AIAgentNode |
|
|
76
78
|
|
|
77
|
-
> Community adds two nodes: TelegramNode and PerformanceReportNode, for
|
|
79
|
+
> Community adds two nodes: TelegramNode and PerformanceReportNode, for 76 total.
|
|
78
80
|
|
|
79
81
|
## 사용 예시
|
|
80
82
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
The 2.6.2 release candidate [futures minute alias correction](../../docs/futures-minute-alias-contract.md) aligns canonical minute periods with the existing one-page o3103 path and rejects unsupported hourly/adjustment claims. Complete-range coverage and consumer adoption are not implied.
|
|
2
|
+
|
|
1
3
|
US regular-session requests can opt into SessionGateNode.exchange_calendar (XNYS/XNAS) for scheduled holidays and early closes. See [session gates](../../docs/session-gates-and-guarded-split.md).
|
|
2
4
|
|
|
3
5
|
# ProgramGarden Core
|
|
@@ -41,13 +43,13 @@ poetry add programgarden-core
|
|
|
41
43
|
|
|
42
44
|
요구 사항: Python 3.12+
|
|
43
45
|
|
|
44
|
-
## Node categories (11 categories,
|
|
46
|
+
## Node categories (11 categories, 74 core nodes)
|
|
45
47
|
|
|
46
48
|
| 카테고리 | 노드 수 | 대표 노드 |
|
|
47
49
|
|----------|---------|----------|
|
|
48
50
|
| infra | 8 | StartNode, BrokerNode, ThrottleNode, SplitNode, AggregateNode, IfNode, KoreaStockBrokerNode |
|
|
49
51
|
| account | 13 | AccountNode, OpenOrdersNode, RealAccountNode, RealOrderEventNode (해외주식/선물 + 국내주식) |
|
|
50
|
-
| market |
|
|
52
|
+
| market | 23 | MarketDataNode, HistoricalDataNode, RealMarketDataNode, WatchlistNode, ExclusionListNode, KoreaStockRankingNode, OverseasStockRankingNode, KoreaStock* |
|
|
51
53
|
| condition | 2 | ConditionNode, LogicNode |
|
|
52
54
|
| order | 10 | NewOrderNode, ModifyOrderNode, CancelOrderNode, PositionSizingNode (해외주식/선물 + 국내주식) |
|
|
53
55
|
| risk | 1 | PortfolioNode |
|
|
@@ -57,7 +59,7 @@ poetry add programgarden-core
|
|
|
57
59
|
| analysis | 2 | BacktestEngineNode, BenchmarkCompareNode |
|
|
58
60
|
| ai | 2 | LLMModelNode, AIAgentNode |
|
|
59
61
|
|
|
60
|
-
> Community adds two nodes: TelegramNode and PerformanceReportNode, for
|
|
62
|
+
> Community adds two nodes: TelegramNode and PerformanceReportNode, for 76 total.
|
|
61
63
|
|
|
62
64
|
## 사용 예시
|
|
63
65
|
|
|
@@ -51,6 +51,7 @@ __all__ = [
|
|
|
51
51
|
"OverseasStockHistoricalDataNode",
|
|
52
52
|
"OverseasStockRealMarketDataNode",
|
|
53
53
|
"OverseasStockSymbolQueryNode",
|
|
54
|
+
"OverseasStockRankingNode",
|
|
54
55
|
# Nodes - Market (해외선물)
|
|
55
56
|
"OverseasFuturesMarketDataNode",
|
|
56
57
|
"OverseasFuturesHistoricalDataNode",
|
|
@@ -63,6 +64,7 @@ __all__ = [
|
|
|
63
64
|
"KoreaStockHistoricalDataNode",
|
|
64
65
|
"KoreaStockRealMarketDataNode",
|
|
65
66
|
"KoreaStockSymbolQueryNode",
|
|
67
|
+
"KoreaStockRankingNode",
|
|
66
68
|
"KoreaStockFundamentalNode",
|
|
67
69
|
# Nodes - Account (해외주식)
|
|
68
70
|
"OverseasStockAccountNode",
|
{programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/i18n/locales/en.json
RENAMED
|
@@ -94,6 +94,10 @@
|
|
|
94
94
|
"nodes.KoreaStockRealOrderEventNode.name": "Korea Stock Real Order Event",
|
|
95
95
|
"nodes.KoreaStockSymbolQueryNode.description": "Queries all tradable symbols on KOSPI/KOSDAQ markets. Uses t9945 API to fetch symbol names and codes. Filter by market type (All, KOSPI, KOSDAQ). Outputs symbol list and count. Requires an upstream KoreaStockBrokerNode. Typical connection: KoreaStockSymbolQueryNode → ConditionNode or → KoreaStockMarketDataNode.",
|
|
96
96
|
"nodes.KoreaStockSymbolQueryNode.name": "Korea Stock Symbols",
|
|
97
|
+
"nodes.KoreaStockRankingNode.description": "Lists today's top domestic stocks by gain, loss, volume, trading value or market cap (LS t1441, t1452, t1463, t1444). Outputs ranked rows, a KoreaStock symbol list and the count. Read-only, real account only. Requires an upstream KoreaStockBrokerNode. Typical connection: KoreaStockRankingNode → CodeNode (pick) → KoreaStockMarketDataNode.",
|
|
98
|
+
"nodes.KoreaStockRankingNode.name": "Korea Stock Ranking",
|
|
99
|
+
"nodes.OverseasStockRankingNode.description": "Lists today's top US stocks by gain, loss, volume, trading value, turnover, market cap or 52-week high/low (LS g3112). Outputs ranked rows, an overseas-stock symbol list and the count. Read-only. Requires an upstream OverseasStockBrokerNode. Typical connection: OverseasStockRankingNode → CodeNode (pick) → OverseasStockMarketDataNode.",
|
|
100
|
+
"nodes.OverseasStockRankingNode.name": "Overseas Stock Ranking",
|
|
97
101
|
"nodes.LineChartNode.description": "Renders a time-series line chart on the workflow canvas. Configure x-axis field (typically date) and y-axis field (price, equity, etc.), with optional signal and side markers for buy/sell visualization. Bind data from HistoricalDataNode, BacktestEngineNode equity curves, or any time-series output. Outputs a 'rendered' signal when display is complete. Typical connection: BacktestEngineNode.equity_curve → LineChartNode.",
|
|
98
102
|
"nodes.LineChartNode.name": "Line Chart",
|
|
99
103
|
"nodes.LLMModelNode.description": "Provides LLM (Large Language Model) API connection for AI Agent nodes. Acts as the authentication gateway for LLM services — similar to BrokerNode pattern. Supports OpenAI, Anthropic, and Google credentials. Configure model ID (e.g., gpt-4o, claude-sonnet-4-5-20250929), temperature, max tokens, seed for reproducibility, and streaming mode. Connect to AIAgentNode via ai_model edge type. Does not execute independently — only provides the connection. Typical connection: LLMModelNode →(ai_model edge)→ AIAgentNode.",
|
|
@@ -116,7 +120,7 @@
|
|
|
116
120
|
"nodes.OverseasFuturesBrokerNode.name": "Futures Broker",
|
|
117
121
|
"nodes.OverseasFuturesCancelOrderNode.description": "Cancels a pending overseas futures order by its original order ID. Requires original_order_id from FuturesOpenOrdersNode or FuturesRealOrderEventNode. Outputs cancel result and cancelled order ID. Rate-limited to 5-second minimum interval. Typical connection: FuturesOpenOrdersNode → FuturesCancelOrderNode.",
|
|
118
122
|
"nodes.OverseasFuturesCancelOrderNode.name": "Futures Cancel Order",
|
|
119
|
-
"nodes.OverseasFuturesHistoricalDataNode.description": "Fetches
|
|
123
|
+
"nodes.OverseasFuturesHistoricalDataNode.description": "Fetches exact-contract overseas-futures OHLCV through an upstream broker. Minute periods use one available o3103 page (200 rows requested); start/end dates are not sent and the requested period is not certified coverage. Completed bars, time zone, retention and sufficient lookback require separate verification. Daily/weekly/monthly use o3108. Rollover adjustment is not implemented; keep adjust=false.",
|
|
120
124
|
"nodes.OverseasFuturesHistoricalDataNode.name": "Futures Historical Data",
|
|
121
125
|
"nodes.OverseasFuturesMarketDataNode.description": "Fetches the current price, volume, and market data for a single overseas futures symbol as a one-time REST API call. Auto-iterates when the previous node outputs an array of symbols. Outputs market data including last price, change, volume, and bid/ask. Requires an upstream OverseasFuturesBrokerNode. Supported exchanges: CME, EUREX, SGX, HKEX. For continuous updates, use OverseasFuturesRealMarketDataNode. Can be used as an AI Agent tool.",
|
|
122
126
|
"nodes.OverseasFuturesMarketDataNode.name": "Futures Market Data",
|
|
@@ -345,6 +349,12 @@
|
|
|
345
349
|
"fields.KoreaStockRealOrderEventNode.event_filter": "Select which Korea stock order notifications to receive. Choose 'All' to get all order events.",
|
|
346
350
|
"fields.KoreaStockRealOrderEventNode.stay_connected": "✅ ON: Continuously receives order fill/reject/cancel notifications.\n❌ OFF: Receives events once and disconnects.",
|
|
347
351
|
"fields.KoreaStockSymbolQueryNode.market": "Select the market to query. Choose All, KOSPI, or KOSDAQ.",
|
|
352
|
+
"fields.KoreaStockRankingNode.ranking_type": "Choose what to rank by: top gainers, top losers, volume, trading value or market cap.",
|
|
353
|
+
"fields.KoreaStockRankingNode.market": "Choose All, KOSPI or KOSDAQ. Market cap ranking needs KOSPI or KOSDAQ.",
|
|
354
|
+
"fields.KoreaStockRankingNode.limit": "Maximum number of ranked stocks to return (1-100).",
|
|
355
|
+
"fields.OverseasStockRankingNode.ranking_type": "Choose what to rank by: top gainers, top losers, volume, trading value, turnover, market cap, 52-week high or 52-week low.",
|
|
356
|
+
"fields.OverseasStockRankingNode.market": "Choose the US segment: All, NYSE, NASDAQ or ETF.",
|
|
357
|
+
"fields.OverseasStockRankingNode.limit": "Maximum number of ranked stocks to return (1-100).",
|
|
348
358
|
"fields.LLMModelNode.credential_id": "LLM API Credential",
|
|
349
359
|
"fields.LLMModelNode.model": "Model",
|
|
350
360
|
"fields.LLMModelNode.model_help": "LLM model ID to use. e.g. gpt-4o, claude-sonnet-4-5-20250929, llama3.1",
|
|
@@ -371,13 +381,13 @@
|
|
|
371
381
|
"fields.OverseasFuturesCancelOrderNode.exchange": "Select the exchange.",
|
|
372
382
|
"fields.OverseasFuturesCancelOrderNode.original_order_id": "Original order ID to cancel.",
|
|
373
383
|
"fields.OverseasFuturesCancelOrderNode.symbol": "Symbol code.",
|
|
374
|
-
"fields.OverseasFuturesHistoricalDataNode.adjust.detail": "
|
|
375
|
-
"fields.OverseasFuturesHistoricalDataNode.adjust.short": "
|
|
384
|
+
"fields.OverseasFuturesHistoricalDataNode.adjust.detail": "Must remain false. Rollover adjustment and cross-contract stitching are not implemented; true is rejected before broker access.",
|
|
385
|
+
"fields.OverseasFuturesHistoricalDataNode.adjust.short": "Exact-contract prices only (false)",
|
|
376
386
|
"fields.OverseasFuturesHistoricalDataNode.end_date": "End date (YYYYMMDD)",
|
|
377
|
-
"fields.OverseasFuturesHistoricalDataNode.end_date.help_text": "e.g., 20241231. With binding: {{ date.today(format='yyyymmdd') }}",
|
|
378
|
-
"fields.OverseasFuturesHistoricalDataNode.interval": "
|
|
387
|
+
"fields.OverseasFuturesHistoricalDataNode.end_date.help_text": "e.g., 20241231. With binding: {{ date.today(format='yyyymmdd') }}. Minute queries do not send this date; the requested period is not actual coverage.",
|
|
388
|
+
"fields.OverseasFuturesHistoricalDataNode.interval": "Implemented periods: 30s, 1m, 5m, 15m, 30m, 1d, 1w, 1M. Hourly and unknown periods are rejected.",
|
|
379
389
|
"fields.OverseasFuturesHistoricalDataNode.start_date": "Start date (YYYYMMDD)",
|
|
380
|
-
"fields.OverseasFuturesHistoricalDataNode.start_date.help_text": "e.g., 20240101. With binding: {{ date.ago(30, format='yyyymmdd') }}",
|
|
390
|
+
"fields.OverseasFuturesHistoricalDataNode.start_date.help_text": "e.g., 20240101. With binding: {{ date.ago(30, format='yyyymmdd') }}. Used by daily/weekly/monthly requests; minute queries do not send this date and return one available page.",
|
|
381
391
|
"fields.OverseasFuturesHistoricalDataNode.symbol": "Enter the futures symbol code to query",
|
|
382
392
|
"fields.OverseasFuturesHistoricalDataNode.symbol.exchange": "Exchange",
|
|
383
393
|
"fields.OverseasFuturesHistoricalDataNode.symbol.help_text": "Direct input or binding available (fx toggle)",
|
|
@@ -638,6 +648,12 @@
|
|
|
638
648
|
"fieldNames.KoreaStockRealOrderEventNode.event_filter": "Event Filter",
|
|
639
649
|
"fieldNames.KoreaStockRealOrderEventNode.stay_connected": "Stay Connected",
|
|
640
650
|
"fieldNames.KoreaStockSymbolQueryNode.market": "Market",
|
|
651
|
+
"fieldNames.KoreaStockRankingNode.ranking_type": "Ranking",
|
|
652
|
+
"fieldNames.KoreaStockRankingNode.market": "Market",
|
|
653
|
+
"fieldNames.KoreaStockRankingNode.limit": "Count",
|
|
654
|
+
"fieldNames.OverseasStockRankingNode.ranking_type": "Ranking",
|
|
655
|
+
"fieldNames.OverseasStockRankingNode.market": "Market",
|
|
656
|
+
"fieldNames.OverseasStockRankingNode.limit": "Count",
|
|
641
657
|
"fieldNames.LineChartNode.data": "Data",
|
|
642
658
|
"fieldNames.LineChartNode.side_field": "Side Field",
|
|
643
659
|
"fieldNames.LineChartNode.signal_field": "Signal Field",
|
|
@@ -956,6 +972,7 @@
|
|
|
956
972
|
"ports.summary": "Performance summary",
|
|
957
973
|
"ports.symbol": "Symbol code",
|
|
958
974
|
"ports.symbols": "List of symbols",
|
|
975
|
+
"ports.rankings": "Ranked rows",
|
|
959
976
|
"ports.target_orders": "Target orders",
|
|
960
977
|
"ports.throttle_stats": "Throttle stats (skip count, countdown, etc.)",
|
|
961
978
|
"ports.tick_data": "Tick data",
|
|
@@ -1027,6 +1044,18 @@
|
|
|
1027
1044
|
"enums.kr_market.KOSDAQ": "KOSDAQ",
|
|
1028
1045
|
"enums.kr_market.KOSPI": "KOSPI",
|
|
1029
1046
|
"enums.kr_market.all": "All",
|
|
1047
|
+
"enums.ranking_type.change_rate_up": "Top gainers",
|
|
1048
|
+
"enums.ranking_type.change_rate_down": "Top losers",
|
|
1049
|
+
"enums.ranking_type.volume": "Volume",
|
|
1050
|
+
"enums.ranking_type.trading_value": "Trading value",
|
|
1051
|
+
"enums.ranking_type.turnover": "Turnover",
|
|
1052
|
+
"enums.ranking_type.market_cap": "Market cap",
|
|
1053
|
+
"enums.ranking_type.high_52w": "52-week high",
|
|
1054
|
+
"enums.ranking_type.low_52w": "52-week low",
|
|
1055
|
+
"enums.us_ranking_market.all": "All",
|
|
1056
|
+
"enums.us_ranking_market.NYSE": "NYSE",
|
|
1057
|
+
"enums.us_ranking_market.NASDAQ": "NASDAQ",
|
|
1058
|
+
"enums.us_ranking_market.ETF": "ETF",
|
|
1030
1059
|
"enums.kr_price_type.conditional_limit": "Conditional Limit",
|
|
1031
1060
|
"enums.kr_price_type.limit": "Limit",
|
|
1032
1061
|
"enums.kr_price_type.market": "Market",
|
|
@@ -1035,6 +1064,8 @@
|
|
|
1035
1064
|
"enums.interval.1Y": "1 year",
|
|
1036
1065
|
"enums.interval.1d": "1 Day",
|
|
1037
1066
|
"enums.interval.1h": "1 Hour",
|
|
1067
|
+
"enums.interval.30s": "30 seconds",
|
|
1068
|
+
"enums.interval.30m": "30 minutes",
|
|
1038
1069
|
"enums.interval.1m": "1 Minute",
|
|
1039
1070
|
"enums.interval.1w": "1 Week",
|
|
1040
1071
|
"enums.interval.5m": "5 Minutes",
|
{programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/i18n/locales/ko.json
RENAMED
|
@@ -94,6 +94,10 @@
|
|
|
94
94
|
"nodes.KoreaStockRealOrderEventNode.name": "국내주식 실시간 주문 이벤트",
|
|
95
95
|
"nodes.KoreaStockSymbolQueryNode.description": "KOSPI/KOSDAQ 전체 거래 가능 종목을 조회합니다. t9945 API로 종목명, 종목코드를 가져옵니다. 시장 구분(전체, KOSPI, KOSDAQ)으로 필터링 가능. 출력: 종목 목록, 종목 수. 상위 KoreaStockBrokerNode 연결 필수. 일반적인 연결: KoreaStockSymbolQueryNode → ConditionNode 또는 → KoreaStockMarketDataNode.",
|
|
96
96
|
"nodes.KoreaStockSymbolQueryNode.name": "국내주식 종목 조회",
|
|
97
|
+
"nodes.KoreaStockRankingNode.description": "오늘의 국내주식 상위 종목을 등락률(상승·하락), 거래량, 거래대금, 시가총액 기준으로 조회합니다 (LS t1441, t1452, t1463, t1444). 출력: 순위 행, 국내주식 종목 리스트, 종목 수. 읽기 전용이며 실계좌 전용입니다. 상위 KoreaStockBrokerNode 연결 필수. 일반적인 연결: KoreaStockRankingNode → CodeNode(선별) → KoreaStockMarketDataNode.",
|
|
98
|
+
"nodes.KoreaStockRankingNode.name": "국내주식 순위",
|
|
99
|
+
"nodes.OverseasStockRankingNode.description": "오늘의 미국 주식 상위 종목을 등락률(상승·하락), 거래량, 거래대금, 회전율, 시가총액, 52주 신고가·신저가 기준으로 조회합니다 (LS g3112). 출력: 순위 행, 해외주식 종목 리스트, 종목 수. 읽기 전용입니다. 상위 OverseasStockBrokerNode 연결 필수. 일반적인 연결: OverseasStockRankingNode → CodeNode(선별) → OverseasStockMarketDataNode.",
|
|
100
|
+
"nodes.OverseasStockRankingNode.name": "해외주식 순위",
|
|
97
101
|
"nodes.LineChartNode.description": "워크플로우 캔버스에 시계열 라인 차트를 렌더링합니다. X축 필드(보통 날짜)와 Y축 필드(가격, 자산 등)를 설정하고, 매수/매도 시각화를 위한 signal/side 마커를 선택적으로 추가합니다. HistoricalDataNode, BacktestEngineNode equity curve 등 시계열 데이터를 바인딩합니다. 표시 완료 시 'rendered' 신호 출력. 일반적인 연결: BacktestEngineNode.equity_curve → LineChartNode.",
|
|
98
102
|
"nodes.LineChartNode.name": "라인차트",
|
|
99
103
|
"nodes.LLMModelNode.description": "AI Agent 노드에 LLM(대규모 언어 모델) API 연결을 제공합니다. BrokerNode와 유사한 인증 게이트웨이 패턴입니다. OpenAI, Anthropic, Google 인증 지원. 모델 ID(예: gpt-4o, claude-sonnet-4-5-20250929), temperature, max tokens, 재현성을 위한 seed, 스트리밍 모드를 설정합니다. ai_model 엣지로 AIAgentNode에 연결합니다. 독립 실행 불가 — 연결만 제공합니다. 일반적인 연결: LLMModelNode →(ai_model 엣지)→ AIAgentNode.",
|
|
@@ -116,7 +120,7 @@
|
|
|
116
120
|
"nodes.OverseasFuturesBrokerNode.name": "해외선물 브로커",
|
|
117
121
|
"nodes.OverseasFuturesCancelOrderNode.description": "해외선물 미체결 주문을 원래 주문 ID로 취소합니다. FuturesOpenOrdersNode 또는 FuturesRealOrderEventNode에서 original_order_id를 받아야 합니다. 출력: 취소 결과, 취소된 주문 ID. 최소 5초 간격 제한 적용. 일반적인 연결: FuturesOpenOrdersNode → FuturesCancelOrderNode.",
|
|
118
122
|
"nodes.OverseasFuturesCancelOrderNode.name": "해외선물 취소주문",
|
|
119
|
-
"nodes.OverseasFuturesHistoricalDataNode.description": "
|
|
123
|
+
"nodes.OverseasFuturesHistoricalDataNode.description": "연결한 증권 계좌로 지정 월물의 OHLCV를 조회합니다. 분봉은 o3103의 첫 페이지를 한 번 조회하며 200건을 요청합니다. 분봉 요청에는 시작·종료 날짜가 전송되지 않으며, 표시된 요청 기간 전체를 조회했다는 뜻이 아닙니다. 완료봉·시간대·보존 범위·필요 봉 수는 별도로 확인해야 합니다. 일·주·월봉은 o3108을 사용합니다. 롤오버 가격 보정은 구현되어 있지 않아 adjust는 false로 유지합니다.",
|
|
120
124
|
"nodes.OverseasFuturesHistoricalDataNode.name": "해외선물 과거데이터",
|
|
121
125
|
"nodes.OverseasFuturesMarketDataNode.description": "해외선물 종목의 현재가, 거래량, 시세 데이터를 REST API 1회 호출로 조회합니다. 이전 노드가 종목 배열을 출력하면 자동 반복 실행합니다. 출력: 최근 체결가, 등락폭, 거래량, 매수/매도 호가. 상위 OverseasFuturesBrokerNode 연결 필수. 지원 거래소: CME, EUREX, SGX, HKEX. 연속 업데이트가 필요하면 OverseasFuturesRealMarketDataNode를 사용하세요. AI Agent 도구로 사용 가능.",
|
|
122
126
|
"nodes.OverseasFuturesMarketDataNode.name": "해외선물 현재가",
|
|
@@ -345,6 +349,12 @@
|
|
|
345
349
|
"fields.KoreaStockRealOrderEventNode.event_filter": "받고 싶은 국내주식 주문 알림을 선택하세요. '전체'를 선택하면 모든 주문 이벤트를 받습니다.",
|
|
346
350
|
"fields.KoreaStockRealOrderEventNode.stay_connected": "✅ 켜면: 주문 체결/거부/취소 알림을 계속 받습니다.\n❌ 끄면: 이벤트를 한 번만 받고 끊깁니다.",
|
|
347
351
|
"fields.KoreaStockSymbolQueryNode.market": "조회할 시장을 선택하세요. 전체, KOSPI(유가증권), KOSDAQ(코스닥) 중 선택합니다.",
|
|
352
|
+
"fields.KoreaStockRankingNode.ranking_type": "순위 기준을 고르세요. 상승률, 하락률, 거래량, 거래대금, 시가총액 중 선택합니다.",
|
|
353
|
+
"fields.KoreaStockRankingNode.market": "전체, KOSPI(유가증권), KOSDAQ(코스닥) 중 선택합니다. 시가총액 순위는 KOSPI 또는 KOSDAQ 을 골라야 합니다.",
|
|
354
|
+
"fields.KoreaStockRankingNode.limit": "가져올 순위 종목 수의 최대값입니다 (1~100).",
|
|
355
|
+
"fields.OverseasStockRankingNode.ranking_type": "순위 기준을 고르세요. 상승률, 하락률, 거래량, 거래대금, 회전율, 시가총액, 52주 신고가, 52주 신저가 중 선택합니다.",
|
|
356
|
+
"fields.OverseasStockRankingNode.market": "미국 시장 구분을 고르세요. 전체, 뉴욕(NYSE), 나스닥(NASDAQ), ETF 중 선택합니다.",
|
|
357
|
+
"fields.OverseasStockRankingNode.limit": "가져올 순위 종목 수의 최대값입니다 (1~100).",
|
|
348
358
|
"fields.LLMModelNode.credential_id": "LLM API 인증정보",
|
|
349
359
|
"fields.LLMModelNode.model": "모델",
|
|
350
360
|
"fields.LLMModelNode.model_help": "사용할 LLM 모델 ID입니다. 예: gpt-4o, claude-sonnet-4-5-20250929, llama3.1",
|
|
@@ -371,13 +381,13 @@
|
|
|
371
381
|
"fields.OverseasFuturesCancelOrderNode.exchange": "거래소를 선택합니다.",
|
|
372
382
|
"fields.OverseasFuturesCancelOrderNode.original_order_id": "취소할 원주문번호입니다.",
|
|
373
383
|
"fields.OverseasFuturesCancelOrderNode.symbol": "종목 코드입니다.",
|
|
374
|
-
"fields.OverseasFuturesHistoricalDataNode.adjust.detail": "롤오버
|
|
375
|
-
"fields.OverseasFuturesHistoricalDataNode.adjust.short": "
|
|
384
|
+
"fields.OverseasFuturesHistoricalDataNode.adjust.detail": "false로 유지합니다. 롤오버 가격 보정과 월물 연결은 구현되어 있지 않으며, true는 증권사 접근 전에 거절됩니다.",
|
|
385
|
+
"fields.OverseasFuturesHistoricalDataNode.adjust.short": "지정 월물 가격만 사용 (false)",
|
|
376
386
|
"fields.OverseasFuturesHistoricalDataNode.end_date": "조회 종료일 (YYYYMMDD)",
|
|
377
|
-
"fields.OverseasFuturesHistoricalDataNode.end_date.help_text": "예: 20241231.
|
|
378
|
-
"fields.OverseasFuturesHistoricalDataNode.interval": "
|
|
387
|
+
"fields.OverseasFuturesHistoricalDataNode.end_date.help_text": "예: 20241231. 바인딩: {{ date.today(format='yyyymmdd') }}. 분봉은 이 날짜를 전송하지 않으며, 표시된 요청 기간이 실제 조회 범위를 보장하지 않습니다.",
|
|
388
|
+
"fields.OverseasFuturesHistoricalDataNode.interval": "지원 주기: 30s, 1m, 5m, 15m, 30m, 1d, 1w, 1M. 1h와 알 수 없는 주기는 거절됩니다.",
|
|
379
389
|
"fields.OverseasFuturesHistoricalDataNode.start_date": "조회 시작일 (YYYYMMDD)",
|
|
380
|
-
"fields.OverseasFuturesHistoricalDataNode.start_date.help_text": "예: 20240101.
|
|
390
|
+
"fields.OverseasFuturesHistoricalDataNode.start_date.help_text": "예: 20240101. 바인딩: {{ date.ago(30, format='yyyymmdd') }}. 일·주·월봉 요청에 사용합니다. 분봉은 이 날짜를 전송하지 않고 첫 페이지를 한 번 조회합니다.",
|
|
381
391
|
"fields.OverseasFuturesHistoricalDataNode.symbol": "조회할 선물 종목 코드를 입력하세요",
|
|
382
392
|
"fields.OverseasFuturesHistoricalDataNode.symbol.exchange": "거래소",
|
|
383
393
|
"fields.OverseasFuturesHistoricalDataNode.symbol.help_text": "직접 입력 또는 바인딩 가능 (fx 토글)",
|
|
@@ -638,6 +648,12 @@
|
|
|
638
648
|
"fieldNames.KoreaStockRealOrderEventNode.event_filter": "이벤트필터",
|
|
639
649
|
"fieldNames.KoreaStockRealOrderEventNode.stay_connected": "연결유지",
|
|
640
650
|
"fieldNames.KoreaStockSymbolQueryNode.market": "시장구분",
|
|
651
|
+
"fieldNames.KoreaStockRankingNode.ranking_type": "순위 기준",
|
|
652
|
+
"fieldNames.KoreaStockRankingNode.market": "시장구분",
|
|
653
|
+
"fieldNames.KoreaStockRankingNode.limit": "종목 수",
|
|
654
|
+
"fieldNames.OverseasStockRankingNode.ranking_type": "순위 기준",
|
|
655
|
+
"fieldNames.OverseasStockRankingNode.market": "시장구분",
|
|
656
|
+
"fieldNames.OverseasStockRankingNode.limit": "종목 수",
|
|
641
657
|
"fieldNames.LineChartNode.data": "데이터",
|
|
642
658
|
"fieldNames.LineChartNode.side_field": "방향필드",
|
|
643
659
|
"fieldNames.LineChartNode.signal_field": "시그널필드",
|
|
@@ -956,6 +972,7 @@
|
|
|
956
972
|
"ports.summary": "성과 요약",
|
|
957
973
|
"ports.symbol": "종목 코드",
|
|
958
974
|
"ports.symbols": "종목 리스트",
|
|
975
|
+
"ports.rankings": "순위 목록",
|
|
959
976
|
"ports.target_orders": "대상 주문",
|
|
960
977
|
"ports.throttle_stats": "쓰로틀 통계 (스킵 횟수, 카운트다운 등)",
|
|
961
978
|
"ports.tick_data": "틱 데이터",
|
|
@@ -1027,6 +1044,18 @@
|
|
|
1027
1044
|
"enums.kr_market.KOSDAQ": "KOSDAQ (코스닥)",
|
|
1028
1045
|
"enums.kr_market.KOSPI": "KOSPI (유가증권)",
|
|
1029
1046
|
"enums.kr_market.all": "전체",
|
|
1047
|
+
"enums.ranking_type.change_rate_up": "상승률 상위",
|
|
1048
|
+
"enums.ranking_type.change_rate_down": "하락률 상위",
|
|
1049
|
+
"enums.ranking_type.volume": "거래량 상위",
|
|
1050
|
+
"enums.ranking_type.trading_value": "거래대금 상위",
|
|
1051
|
+
"enums.ranking_type.turnover": "회전율 상위",
|
|
1052
|
+
"enums.ranking_type.market_cap": "시가총액 상위",
|
|
1053
|
+
"enums.ranking_type.high_52w": "52주 신고가",
|
|
1054
|
+
"enums.ranking_type.low_52w": "52주 신저가",
|
|
1055
|
+
"enums.us_ranking_market.all": "전체",
|
|
1056
|
+
"enums.us_ranking_market.NYSE": "뉴욕(NYSE)",
|
|
1057
|
+
"enums.us_ranking_market.NASDAQ": "나스닥(NASDAQ)",
|
|
1058
|
+
"enums.us_ranking_market.ETF": "ETF",
|
|
1030
1059
|
"enums.kr_price_type.conditional_limit": "조건부지정가 (Conditional Limit)",
|
|
1031
1060
|
"enums.kr_price_type.limit": "지정가 (Limit)",
|
|
1032
1061
|
"enums.kr_price_type.market": "시장가 (Market)",
|
|
@@ -1035,6 +1064,8 @@
|
|
|
1035
1064
|
"enums.interval.1Y": "1년",
|
|
1036
1065
|
"enums.interval.1d": "1일",
|
|
1037
1066
|
"enums.interval.1h": "1시간",
|
|
1067
|
+
"enums.interval.30s": "30초",
|
|
1068
|
+
"enums.interval.30m": "30분",
|
|
1038
1069
|
"enums.interval.1m": "1분",
|
|
1039
1070
|
"enums.interval.1w": "1주",
|
|
1040
1071
|
"enums.interval.5m": "5분",
|
|
@@ -100,6 +100,8 @@ from programgarden_core.nodes.data_korea_stock import KoreaStockMarketDataNode
|
|
|
100
100
|
from programgarden_core.nodes.fundamental_korea_stock import KoreaStockFundamentalNode
|
|
101
101
|
from programgarden_core.nodes.backtest_korea_stock import KoreaStockHistoricalDataNode
|
|
102
102
|
from programgarden_core.nodes.symbol_korea_stock import KoreaStockSymbolQueryNode
|
|
103
|
+
from programgarden_core.nodes.ranking_korea_stock import KoreaStockRankingNode
|
|
104
|
+
from programgarden_core.nodes.ranking_stock import OverseasStockRankingNode
|
|
103
105
|
from programgarden_core.nodes.realtime_korea_stock import (
|
|
104
106
|
KoreaStockRealMarketDataNode,
|
|
105
107
|
KoreaStockRealAccountNode,
|
|
@@ -196,6 +198,8 @@ __all__ = [
|
|
|
196
198
|
"KoreaStockHistoricalDataNode",
|
|
197
199
|
"KoreaStockRealMarketDataNode",
|
|
198
200
|
"KoreaStockSymbolQueryNode",
|
|
201
|
+
"KoreaStockRankingNode",
|
|
202
|
+
"OverseasStockRankingNode",
|
|
199
203
|
# Account - Korea Stock (국내주식)
|
|
200
204
|
"KoreaStockAccountNode",
|
|
201
205
|
"KoreaStockOpenOrdersNode",
|
{programgarden_core-2.6.1 → programgarden_core-2.6.3}/programgarden_core/nodes/backtest_futures.py
RENAMED
|
@@ -10,7 +10,7 @@ Item-based execution:
|
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
from typing import Any, Optional, List, Literal, Dict, ClassVar, TYPE_CHECKING
|
|
13
|
-
from pydantic import Field
|
|
13
|
+
from pydantic import Field, field_validator
|
|
14
14
|
|
|
15
15
|
if TYPE_CHECKING:
|
|
16
16
|
from programgarden_core.models.field_binding import FieldSchema
|
|
@@ -59,21 +59,27 @@ class OverseasFuturesHistoricalDataNode(BaseNode):
|
|
|
59
59
|
)
|
|
60
60
|
start_date: str = Field(
|
|
61
61
|
default="{{ date.months_ago(3, format='yyyymmdd') }}",
|
|
62
|
-
description="
|
|
62
|
+
description="Requested start date (YYYYMMDD or expression); not sent for minute periods.",
|
|
63
63
|
)
|
|
64
64
|
end_date: str = Field(
|
|
65
65
|
default="{{ date.today(format='yyyymmdd') }}",
|
|
66
|
-
description="
|
|
66
|
+
description="Requested end date (YYYYMMDD or expression); not sent for minute periods.",
|
|
67
67
|
)
|
|
68
|
-
interval:
|
|
68
|
+
interval: Literal["30s", "1m", "5m", "15m", "30m", "1d", "1w", "1M"] = Field(
|
|
69
69
|
default="1d",
|
|
70
|
-
description="
|
|
70
|
+
description="Implemented chart periods: 30s, 1m, 5m, 15m, 30m, 1d, 1w, 1M; hourly and unknown periods are rejected.",
|
|
71
71
|
)
|
|
72
|
-
adjust:
|
|
72
|
+
adjust: Literal[False] = Field(
|
|
73
73
|
default=False,
|
|
74
|
-
description="
|
|
74
|
+
description="Must remain false; only exact-contract prices are implemented, without rollover adjustment.",
|
|
75
75
|
)
|
|
76
76
|
|
|
77
|
+
@field_validator("interval", mode="before")
|
|
78
|
+
@classmethod
|
|
79
|
+
def normalize_legacy_interval(cls, value):
|
|
80
|
+
aliases = {"1min": "1m", "5min": "5m", "15min": "15m", "30min": "30m"}
|
|
81
|
+
return aliases.get(value, value) if isinstance(value, str) else value
|
|
82
|
+
|
|
77
83
|
@classmethod
|
|
78
84
|
def is_tool_enabled(cls) -> bool:
|
|
79
85
|
return True
|
|
@@ -82,7 +88,7 @@ class OverseasFuturesHistoricalDataNode(BaseNode):
|
|
|
82
88
|
"when_to_use": [
|
|
83
89
|
"Retrieve daily (or intraday) OHLCV history for an overseas futures contract (CME, EUREX, SGX, HKEX) for technical analysis or backtesting",
|
|
84
90
|
"Feed historical candles into ConditionNode plugins (MACD, Bollinger, etc.) that operate on futures price series",
|
|
85
|
-
"Use
|
|
91
|
+
"Use date expressions for daily/weekly/monthly request dates; minute requests do not send dates or guarantee a lookback window",
|
|
86
92
|
],
|
|
87
93
|
"when_not_to_use": [
|
|
88
94
|
"For overseas stock historical data — use OverseasStockHistoricalDataNode",
|
|
@@ -97,9 +103,11 @@ class OverseasFuturesHistoricalDataNode(BaseNode):
|
|
|
97
103
|
}
|
|
98
104
|
_features: ClassVar[List[str]] = [
|
|
99
105
|
"Returns time_series list of OHLCV candles: [{date, open, high, low, close, volume}, ...] ordered oldest-first",
|
|
100
|
-
"Supports
|
|
106
|
+
"Supports implemented periods: 30s, 1m, 5m, 15m, 30m, 1d, 1w, 1M; legacy minute aliases are accepted; 1h and unknown periods are rejected",
|
|
101
107
|
"start_date / end_date accept YYYYMMDD strings or `{{ date.ago(N, format='yyyymmdd') }}` expressions",
|
|
102
|
-
"adjust
|
|
108
|
+
"adjust must remain false: exact-contract prices only, without rollover adjustment or month stitching",
|
|
109
|
+
"Minute history returns the available initial o3103 page (200 rows requested), not a complete requested range or a guaranteed latest-N set",
|
|
110
|
+
"Minute start/end dates are not sent to o3103; period echoes requested dates, not actual coverage. Bar finality, time zone, retention and sufficient lookback require separate evidence",
|
|
103
111
|
"is_tool_enabled=True — AI Agent can fetch futures history for technical analysis autonomously",
|
|
104
112
|
"Item-based execution: pair with SplitNode to fetch OHLCV for multiple contracts",
|
|
105
113
|
"Replay resolves this node's request with the upstream broker's connection identity (provider, product, paper_trading, broker_node_id, and credential_id when the account is linked); a recording whose request omits that connection does not match",
|
|
@@ -117,9 +125,9 @@ class OverseasFuturesHistoricalDataNode(BaseNode):
|
|
|
117
125
|
"alternative": "Bind `{{ nodes.historical.value.time_series }}` to the ConditionNode data field.",
|
|
118
126
|
},
|
|
119
127
|
{
|
|
120
|
-
"pattern": "
|
|
121
|
-
"reason": "
|
|
122
|
-
"alternative": "
|
|
128
|
+
"pattern": "Treating exact-contract observations as continuous or rollover-adjusted data",
|
|
129
|
+
"reason": "Rollover adjustment and cross-contract stitching are not implemented.",
|
|
130
|
+
"alternative": "Keep adjust=False and verify this contract has the needed data; do not substitute internal history.",
|
|
123
131
|
},
|
|
124
132
|
]
|
|
125
133
|
_examples: ClassVar[List[Dict[str, Any]]] = [
|
|
@@ -158,7 +166,7 @@ class OverseasFuturesHistoricalDataNode(BaseNode):
|
|
|
158
166
|
},
|
|
159
167
|
{
|
|
160
168
|
"title": "HKEX mini-futures intraday scan",
|
|
161
|
-
"description": "
|
|
169
|
+
"description": "Request the available initial 30-minute page for HKEX mini-futures; verify completed bars and lookback before MACD.",
|
|
162
170
|
"workflow_snippet": {
|
|
163
171
|
"id": "overseas_futures_historical_hkex_macd",
|
|
164
172
|
"name": "HKEX Intraday MACD",
|
|
@@ -166,7 +174,7 @@ class OverseasFuturesHistoricalDataNode(BaseNode):
|
|
|
166
174
|
{"id": "start", "type": "StartNode"},
|
|
167
175
|
{"id": "broker", "type": "OverseasFuturesBrokerNode", "credential_id": "broker_cred", "paper_trading": False},
|
|
168
176
|
{'id': 'split', 'type': 'SplitNode', 'array': [{'symbol': 'MHIH26', 'exchange': 'HKEX'}]},
|
|
169
|
-
{"id": "historical", "type": "OverseasFuturesHistoricalDataNode", "symbol": "{{ nodes.split.item }}", "start_date": "{{ date.ago(10, format='yyyymmdd') }}", "end_date": "{{ date.today(format='yyyymmdd') }}", "interval": "
|
|
177
|
+
{"id": "historical", "type": "OverseasFuturesHistoricalDataNode", "symbol": "{{ nodes.split.item }}", "start_date": "{{ date.ago(10, format='yyyymmdd') }}", "end_date": "{{ date.today(format='yyyymmdd') }}", "interval": "30m", "adjust": False},
|
|
170
178
|
{"id": "condition", "type": "ConditionNode", "plugin": "MACD", "items": {"from": "{{ item.time_series }}", "extract": {"symbol": "{{ item.symbol }}", "exchange": "{{ item.exchange }}", "date": "{{ row.date }}", "close": "{{ row.close }}"}}, "fields": {"fast": 12, "slow": 26, "signal": 9, "direction": "bullish_cross"}},
|
|
171
179
|
{'id': 'split_results', 'type': 'AggregateNode', 'mode': 'collect'}],
|
|
172
180
|
"edges": [
|
|
@@ -187,7 +195,7 @@ class OverseasFuturesHistoricalDataNode(BaseNode):
|
|
|
187
195
|
}
|
|
188
196
|
],
|
|
189
197
|
},
|
|
190
|
-
"expected_output": "
|
|
198
|
+
"expected_output": "Available 30-minute observations only; complete range, finality and sufficient lookback are not certified.",
|
|
191
199
|
},
|
|
192
200
|
]
|
|
193
201
|
_node_guide: ClassVar[Dict[str, Any]] = {
|
|
@@ -195,7 +203,7 @@ class OverseasFuturesHistoricalDataNode(BaseNode):
|
|
|
195
203
|
"The `symbol` field takes a single {exchange, symbol} dict — bind to `{{ nodes.split.item }}` for multi-contract iteration. "
|
|
196
204
|
"Exchange values: CME, EUREX, SGX, HKEX. Symbol includes contract month code (e.g., ESH26). "
|
|
197
205
|
"start_date / end_date: use `{{ date.ago(N, format='yyyymmdd') }}` for rolling lookback. "
|
|
198
|
-
"interval options: 1m, 5m, 15m,
|
|
206
|
+
"interval options: 30s, 1m, 5m, 15m, 30m, 1d, 1w, 1M. Minute queries return one available page, not a complete requested date range."
|
|
199
207
|
),
|
|
200
208
|
"output_consumption": (
|
|
201
209
|
"The `value` port emits {symbol, exchange, time_series: [{date, open, high, low, close, volume}, ...]}. "
|
|
@@ -221,9 +229,9 @@ class OverseasFuturesHistoricalDataNode(BaseNode):
|
|
|
221
229
|
OutputPort(name="value", type="ohlcv_data", description="i18n:ports.ohlcv_value", fields=HISTORICAL_VALUE_FIELDS),
|
|
222
230
|
]
|
|
223
231
|
|
|
224
|
-
_version: ClassVar[str] = "1.
|
|
225
|
-
_updated_at: ClassVar[str] = "2026-
|
|
226
|
-
_change_note: ClassVar[Optional[str]] =
|
|
232
|
+
_version: ClassVar[str] = "1.1.0"
|
|
233
|
+
_updated_at: ClassVar[str] = "2026-10-14"
|
|
234
|
+
_change_note: ClassVar[Optional[str]] = "Align minute aliases with one-page chart routing; reject unsupported periods and rollover adjustment."
|
|
227
235
|
|
|
228
236
|
@classmethod
|
|
229
237
|
def get_field_schema(cls) -> Dict[str, "FieldSchema"]:
|
|
@@ -296,12 +304,13 @@ class OverseasFuturesHistoricalDataNode(BaseNode):
|
|
|
296
304
|
description="i18n:fields.OverseasFuturesHistoricalDataNode.interval",
|
|
297
305
|
default="1d",
|
|
298
306
|
required=True,
|
|
299
|
-
enum_values=["1m", "5m", "15m", "
|
|
307
|
+
enum_values=["30s", "1m", "5m", "15m", "30m", "1d", "1w", "1M"],
|
|
300
308
|
enum_labels={
|
|
309
|
+
"30s": "i18n:enums.interval.30s",
|
|
301
310
|
"1m": "i18n:enums.interval.1m",
|
|
302
311
|
"5m": "i18n:enums.interval.5m",
|
|
303
312
|
"15m": "i18n:enums.interval.15m",
|
|
304
|
-
"
|
|
313
|
+
"30m": "i18n:enums.interval.30m",
|
|
305
314
|
"1d": "i18n:enums.interval.1d",
|
|
306
315
|
"1w": "i18n:enums.interval.1w",
|
|
307
316
|
"1M": "i18n:enums.interval.1M"
|
|
@@ -319,8 +328,9 @@ class OverseasFuturesHistoricalDataNode(BaseNode):
|
|
|
319
328
|
help_text="i18n:fields.OverseasFuturesHistoricalDataNode.adjust.detail",
|
|
320
329
|
default=False,
|
|
321
330
|
category=FieldCategory.PARAMETERS,
|
|
322
|
-
expression_mode=ExpressionMode.
|
|
331
|
+
expression_mode=ExpressionMode.FIXED_ONLY,
|
|
323
332
|
ui_component=UIComponent.CHECKBOX,
|
|
324
|
-
example=
|
|
333
|
+
example=False,
|
|
334
|
+
expected_type="bool",
|
|
325
335
|
),
|
|
326
336
|
}
|
|
@@ -185,6 +185,72 @@ KOREA_STOCK_SYMBOL_QUERY_FIELDS: List[Dict[str, str]] = [
|
|
|
185
185
|
{"name": "product", "type": "string", "description": "상품 구분 (항상 korea_stock)"},
|
|
186
186
|
]
|
|
187
187
|
|
|
188
|
+
# ── KoreaStockRankingNode.rankings (t1441 / t1452 / t1463 / t1444) ──
|
|
189
|
+
# Values are consumed as returned by LS; units are named, never converted.
|
|
190
|
+
KOREA_STOCK_RANKING_FIELDS: List[Dict[str, str]] = [
|
|
191
|
+
{"name": "rank", "type": "integer", "description": "1-based rank in this result"},
|
|
192
|
+
{"name": "symbol", "type": "string", "description": "6-digit KRX code (shcode)"},
|
|
193
|
+
{"name": "exchange", "type": "string", "description": "Always KRX"},
|
|
194
|
+
{"name": "market", "type": "string", "description": "KOSPI/KOSDAQ when the request named a market; null for market=all"},
|
|
195
|
+
{"name": "name", "type": "string", "description": "Issue name (hname)"},
|
|
196
|
+
{"name": "price", "type": "number", "description": "Current price"},
|
|
197
|
+
{"name": "open", "type": "number", "description": "Session open (t1441 only; null otherwise)"},
|
|
198
|
+
{"name": "high", "type": "number", "description": "Session high (t1441 only; null otherwise)"},
|
|
199
|
+
{"name": "low", "type": "number", "description": "Session low (t1441 only; null otherwise)"},
|
|
200
|
+
{"name": "sign", "type": "string", "description": "Raw LS direction code (1 upper limit, 2 up, 3 unchanged, 4 lower limit, 5 down)"},
|
|
201
|
+
{"name": "change", "type": "number", "description": "Change vs previous close, signed from the sign code"},
|
|
202
|
+
{"name": "change_pct", "type": "number", "description": "Change percent vs previous close, signed from the sign code"},
|
|
203
|
+
{"name": "volume", "type": "number", "description": "Cumulative volume (shares)"},
|
|
204
|
+
{"name": "trading_value", "type": "number", "description": "Trading value as returned (t1441/t1463; null otherwise)"},
|
|
205
|
+
{"name": "trading_value_unit", "type": "string", "description": "as_returned (t1441) or KRW_million (t1463); null when trading_value is null"},
|
|
206
|
+
{"name": "market_cap", "type": "number", "description": "Market capitalisation as returned (t1441/t1463/t1444; null for t1452)"},
|
|
207
|
+
{"name": "market_cap_unit", "type": "string", "description": "as_returned (t1441), KRW_million (t1463) or KRW_100million (t1444); null when market_cap is null"},
|
|
208
|
+
{"name": "product", "type": "string", "description": "Always korea_stock"},
|
|
209
|
+
{"name": "source_tr", "type": "string", "description": "LS TR that produced the row (t1441/t1452/t1463/t1444)"},
|
|
210
|
+
]
|
|
211
|
+
|
|
212
|
+
# ── KoreaStockRankingNode.symbols ──
|
|
213
|
+
KOREA_STOCK_RANKING_SYMBOL_FIELDS: List[Dict[str, str]] = [
|
|
214
|
+
{"name": "exchange", "type": "string", "description": "Always KRX"},
|
|
215
|
+
{"name": "market", "type": "string", "description": "KOSPI/KOSDAQ when the request named a market; null for market=all"},
|
|
216
|
+
{"name": "symbol", "type": "string", "description": "6-digit KRX code"},
|
|
217
|
+
{"name": "name", "type": "string", "description": "Issue name"},
|
|
218
|
+
{"name": "product", "type": "string", "description": "Always korea_stock"},
|
|
219
|
+
]
|
|
220
|
+
|
|
221
|
+
# ── OverseasStockRankingNode.rankings (g3112) ──
|
|
222
|
+
OVERSEAS_STOCK_RANKING_FIELDS: List[Dict[str, str]] = [
|
|
223
|
+
{"name": "rank", "type": "integer", "description": "1-based rank in this result"},
|
|
224
|
+
{"name": "symbol", "type": "string", "description": "Ticker symbol"},
|
|
225
|
+
{"name": "exchange", "type": "string", "description": "NYSE or NASDAQ from the LS key symbol prefix (81/82); null when unavailable"},
|
|
226
|
+
{"name": "exchange_source", "type": "string", "description": "keysymbol when derived from the LS key symbol, otherwise unavailable"},
|
|
227
|
+
{"name": "name", "type": "string", "description": "Korean issue name (korname)"},
|
|
228
|
+
{"name": "exchange_name", "type": "string", "description": "LS exchange label and symbol as returned (exsymbol, e.g. '나스닥 AEHL')"},
|
|
229
|
+
{"name": "keysymbol", "type": "string", "description": "LS key symbol as returned"},
|
|
230
|
+
{"name": "price", "type": "number", "description": "Current price"},
|
|
231
|
+
{"name": "sign", "type": "string", "description": "Raw LS direction code"},
|
|
232
|
+
{"name": "change", "type": "number", "description": "Change vs previous close, signed from the sign code"},
|
|
233
|
+
{"name": "change_pct", "type": "number", "description": "Change percent vs previous close, signed from the sign code"},
|
|
234
|
+
{"name": "volume", "type": "number", "description": "Volume"},
|
|
235
|
+
{"name": "trading_value", "type": "number", "description": "Trading value as returned by LS (unit not declared)"},
|
|
236
|
+
{"name": "trading_value_unit", "type": "string", "description": "as_returned; null when trading_value is null"},
|
|
237
|
+
{"name": "turnover", "type": "number", "description": "Turnover as returned by LS"},
|
|
238
|
+
{"name": "market_cap", "type": "number", "description": "Market capitalisation as returned by LS (unit not declared)"},
|
|
239
|
+
{"name": "market_cap_unit", "type": "string", "description": "as_returned; null when market_cap is null"},
|
|
240
|
+
{"name": "high_52w", "type": "number", "description": "52-week high"},
|
|
241
|
+
{"name": "low_52w", "type": "number", "description": "52-week low"},
|
|
242
|
+
{"name": "product", "type": "string", "description": "Always overseas_stock"},
|
|
243
|
+
{"name": "source_tr", "type": "string", "description": "Always g3112"},
|
|
244
|
+
]
|
|
245
|
+
|
|
246
|
+
# ── OverseasStockRankingNode.symbols ── (rows without a known exchange are omitted)
|
|
247
|
+
OVERSEAS_STOCK_RANKING_SYMBOL_FIELDS: List[Dict[str, str]] = [
|
|
248
|
+
{"name": "exchange", "type": "string", "description": "NYSE or NASDAQ"},
|
|
249
|
+
{"name": "symbol", "type": "string", "description": "Ticker symbol"},
|
|
250
|
+
{"name": "name", "type": "string", "description": "Korean issue name"},
|
|
251
|
+
{"name": "product", "type": "string", "description": "Always overseas_stock"},
|
|
252
|
+
]
|
|
253
|
+
|
|
188
254
|
# ── OverseasFuturesSymbolQueryNode.symbols (o3101 마스터) ──
|
|
189
255
|
OVERSEAS_FUTURES_SYMBOL_QUERY_FIELDS: List[Dict[str, str]] = [
|
|
190
256
|
{"name": "exchange", "type": "string", "description": "거래소 코드 (CME, HKEX 등 — 주문에 쓰는 값)"},
|