programgarden-core 2.6.2__tar.gz → 2.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/PKG-INFO +4 -4
  2. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/README.md +3 -3
  3. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/__init__.py +2 -0
  4. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/i18n/locales/en.json +33 -2
  5. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/i18n/locales/ko.json +33 -2
  6. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/__init__.py +4 -0
  7. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/backtest_stock.py +56 -8
  8. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/base.py +66 -0
  9. programgarden_core-2.7.0/programgarden_core/nodes/ranking_korea_stock.py +277 -0
  10. programgarden_core-2.7.0/programgarden_core/nodes/ranking_stock.py +248 -0
  11. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/registry/node_registry.py +2 -0
  12. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/pyproject.toml +1 -1
  13. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/bases/__init__.py +0 -0
  14. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/bases/client.py +0 -0
  15. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/bases/components.py +0 -0
  16. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/bases/listener.py +0 -0
  17. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/bases/mixins.py +0 -0
  18. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/bases/products.py +0 -0
  19. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/bases/sql.py +0 -0
  20. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/bases/storage.py +0 -0
  21. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/code_node.py +0 -0
  22. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/exceptions.py +0 -0
  23. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/expression/__init__.py +0 -0
  24. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/expression/evaluator.py +0 -0
  25. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/expression/reference.py +0 -0
  26. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/i18n/__init__.py +0 -0
  27. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/i18n/translator.py +0 -0
  28. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/korea_alias.py +0 -0
  29. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/market_calendar.py +0 -0
  30. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/models/__init__.py +0 -0
  31. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/models/connection_rule.py +0 -0
  32. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/models/credential.py +0 -0
  33. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/models/edge.py +0 -0
  34. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/models/event.py +0 -0
  35. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/models/exchange.py +0 -0
  36. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/models/field_binding.py +0 -0
  37. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/models/job.py +0 -0
  38. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/models/order_diagnostics.py +0 -0
  39. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/models/plugin_resource.py +0 -0
  40. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/models/resilience.py +0 -0
  41. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/models/resource.py +0 -0
  42. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/models/validation.py +0 -0
  43. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/models/workflow.py +0 -0
  44. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/account_futures.py +0 -0
  45. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/account_korea_stock.py +0 -0
  46. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/account_stock.py +0 -0
  47. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/ai.py +0 -0
  48. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/backtest.py +0 -0
  49. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/backtest_futures.py +0 -0
  50. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/backtest_korea_stock.py +0 -0
  51. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/broker.py +0 -0
  52. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/calculation.py +0 -0
  53. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/code.py +0 -0
  54. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/condition.py +0 -0
  55. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/contract_info_futures.py +0 -0
  56. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/data.py +0 -0
  57. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/data_futures.py +0 -0
  58. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/data_korea_stock.py +0 -0
  59. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/data_stock.py +0 -0
  60. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/display.py +0 -0
  61. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/event.py +0 -0
  62. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/fundamental_korea_stock.py +0 -0
  63. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/fundamental_stock.py +0 -0
  64. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/infra.py +0 -0
  65. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/open_orders_futures.py +0 -0
  66. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/open_orders_korea_stock.py +0 -0
  67. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/open_orders_stock.py +0 -0
  68. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/order.py +0 -0
  69. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/orderable_quantity_futures.py +0 -0
  70. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/portfolio.py +0 -0
  71. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/realtime_futures.py +0 -0
  72. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/realtime_korea_stock.py +0 -0
  73. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/realtime_stock.py +0 -0
  74. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/risk.py +0 -0
  75. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/session_gate.py +0 -0
  76. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/symbol.py +0 -0
  77. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/symbol_futures.py +0 -0
  78. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/symbol_korea_stock.py +0 -0
  79. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/symbol_stock.py +0 -0
  80. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/nodes/trigger.py +0 -0
  81. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/presets/__init__.py +0 -0
  82. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/presets/news_analyst.json +0 -0
  83. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/presets/risk_manager.json +0 -0
  84. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/presets/strategist.json +0 -0
  85. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/presets/technical_analyst.json +0 -0
  86. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/registry/__init__.py +0 -0
  87. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/registry/credential_registry.py +0 -0
  88. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/programgarden_core/registry/plugin_registry.py +0 -0
  89. {programgarden_core-2.6.2 → programgarden_core-2.7.0}/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.2
3
+ Version: 2.7.0
4
4
  Summary: ProgramGarden Core - 노드 기반 DSL 핵심 타입 정의
5
5
  License-Expression: AGPL-3.0-or-later
6
6
  Author: 프로그램동산
@@ -60,13 +60,13 @@ poetry add programgarden-core
60
60
 
61
61
  요구 사항: Python 3.12+
62
62
 
63
- ## Node categories (11 categories, 71 core nodes)
63
+ ## Node categories (11 categories, 74 core nodes)
64
64
 
65
65
  | 카테고리 | 노드 수 | 대표 노드 |
66
66
  |----------|---------|----------|
67
67
  | infra | 8 | StartNode, BrokerNode, ThrottleNode, SplitNode, AggregateNode, IfNode, KoreaStockBrokerNode |
68
68
  | account | 13 | AccountNode, OpenOrdersNode, RealAccountNode, RealOrderEventNode (해외주식/선물 + 국내주식) |
69
- | market | 20 | MarketDataNode, HistoricalDataNode, RealMarketDataNode, WatchlistNode, ExclusionListNode, KoreaStock* |
69
+ | market | 23 | MarketDataNode, HistoricalDataNode, RealMarketDataNode, WatchlistNode, ExclusionListNode, KoreaStockRankingNode, OverseasStockRankingNode, KoreaStock* |
70
70
  | condition | 2 | ConditionNode, LogicNode |
71
71
  | order | 10 | NewOrderNode, ModifyOrderNode, CancelOrderNode, PositionSizingNode (해외주식/선물 + 국내주식) |
72
72
  | risk | 1 | PortfolioNode |
@@ -76,7 +76,7 @@ poetry add programgarden-core
76
76
  | analysis | 2 | BacktestEngineNode, BenchmarkCompareNode |
77
77
  | ai | 2 | LLMModelNode, AIAgentNode |
78
78
 
79
- > Community adds two nodes: TelegramNode and PerformanceReportNode, for 73 total.
79
+ > Community adds two nodes: TelegramNode and PerformanceReportNode, for 76 total.
80
80
 
81
81
  ## 사용 예시
82
82
 
@@ -43,13 +43,13 @@ poetry add programgarden-core
43
43
 
44
44
  요구 사항: Python 3.12+
45
45
 
46
- ## Node categories (11 categories, 71 core nodes)
46
+ ## Node categories (11 categories, 74 core nodes)
47
47
 
48
48
  | 카테고리 | 노드 수 | 대표 노드 |
49
49
  |----------|---------|----------|
50
50
  | infra | 8 | StartNode, BrokerNode, ThrottleNode, SplitNode, AggregateNode, IfNode, KoreaStockBrokerNode |
51
51
  | account | 13 | AccountNode, OpenOrdersNode, RealAccountNode, RealOrderEventNode (해외주식/선물 + 국내주식) |
52
- | market | 20 | MarketDataNode, HistoricalDataNode, RealMarketDataNode, WatchlistNode, ExclusionListNode, KoreaStock* |
52
+ | market | 23 | MarketDataNode, HistoricalDataNode, RealMarketDataNode, WatchlistNode, ExclusionListNode, KoreaStockRankingNode, OverseasStockRankingNode, KoreaStock* |
53
53
  | condition | 2 | ConditionNode, LogicNode |
54
54
  | order | 10 | NewOrderNode, ModifyOrderNode, CancelOrderNode, PositionSizingNode (해외주식/선물 + 국내주식) |
55
55
  | risk | 1 | PortfolioNode |
@@ -59,7 +59,7 @@ poetry add programgarden-core
59
59
  | analysis | 2 | BacktestEngineNode, BenchmarkCompareNode |
60
60
  | ai | 2 | LLMModelNode, AIAgentNode |
61
61
 
62
- > Community adds two nodes: TelegramNode and PerformanceReportNode, for 73 total.
62
+ > Community adds two nodes: TelegramNode and PerformanceReportNode, for 76 total.
63
63
 
64
64
  ## 사용 예시
65
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",
@@ -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.",
@@ -140,7 +144,7 @@
140
144
  "nodes.OverseasStockBrokerNode.name": "Stock Broker",
141
145
  "nodes.OverseasStockCancelOrderNode.description": "Cancels a pending US stock order by its original order ID. Requires original_order_id from OverseasStockOpenOrdersNode or OverseasStockRealOrderEventNode. Outputs cancel result and cancelled order ID. Rate-limited to 5-second minimum interval. Typical connection: StockOpenOrdersNode → StockCancelOrderNode, or StockRealOrderEventNode → StockCancelOrderNode.",
142
146
  "nodes.OverseasStockCancelOrderNode.name": "Stock Cancel Order",
143
- "nodes.OverseasStockHistoricalDataNode.description": "Fetches historical OHLCV (Open, High, Low, Close, Volume) chart data for overseas stocks over a specified date range. Uses LS g3204 for daily, weekly, monthly and yearly bars. Intraday g3203 is unsupported. Enable 'adjust' for split/dividend-adjusted prices (recommended for backtesting). Auto-iterates when previous node outputs multiple symbols. Requires an upstream OverseasStockBrokerNode. Typical connection: WatchlistNode → StockHistoricalDataNode → ConditionNode or → BacktestEngineNode. Supported exchanges: NYSE, NASDAQ, AMEX. Can be used as an AI Agent tool.",
147
+ "nodes.OverseasStockHistoricalDataNode.description": "Fetches historical OHLCV (Open, High, Low, Close, Volume) chart data for overseas stocks over a specified date range. Uses LS g3204 for daily, weekly, monthly and yearly bars and LS g3203 for 1/5/10/15/30/60-minute bars (one page of the newest up to 500 bars). Enable 'adjust' for split/dividend-adjusted prices (recommended for backtesting). Auto-iterates when previous node outputs multiple symbols. Requires an upstream OverseasStockBrokerNode. Typical connection: WatchlistNode → StockHistoricalDataNode → ConditionNode or → BacktestEngineNode. Supported exchanges: NYSE, NASDAQ, AMEX. Can be used as an AI Agent tool.",
144
148
  "nodes.OverseasStockHistoricalDataNode.name": "Stock Historical Data",
145
149
  "nodes.OverseasStockFundamentalNode.description": "Fetches fundamental financial data for overseas stocks via LS Securities API. Provides 16 metrics including PER, EPS, PBR, market capitalization, dividend yield, 52-week high/low, and more. Auto-iterates when previous node outputs multiple symbols. Requires an upstream OverseasStockBrokerNode. Typical connection: WatchlistNode → StockFundamentalNode → ConditionNode (for value-based screening). Supported exchanges: NYSE, NASDAQ, AMEX. Can be used as an AI Agent tool.",
146
150
  "nodes.OverseasStockFundamentalNode.name": "Stock Fundamentals",
@@ -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",
@@ -420,7 +430,7 @@
420
430
  "fields.OverseasStockHistoricalDataNode.adjust.short": "Apply adjusted price",
421
431
  "fields.OverseasStockHistoricalDataNode.end_date": "End date (YYYYMMDD)",
422
432
  "fields.OverseasStockHistoricalDataNode.end_date.help_text": "e.g., 20241231. With binding: {{ date.today(format='yyyymmdd') }}",
423
- "fields.OverseasStockHistoricalDataNode.interval": "LS g3204 interval (1d, 1w, 1M, 1Y); intraday is unsupported",
433
+ "fields.OverseasStockHistoricalDataNode.interval": "Bar size: 1d, 1w, 1M, 1Y (LS g3204) or 1m, 5m, 10m, 15m, 30m, 60m minute bars (LS g3203, newest up to 500 bars)",
424
434
  "fields.OverseasStockHistoricalDataNode.start_date": "Start date (YYYYMMDD)",
425
435
  "fields.OverseasStockHistoricalDataNode.start_date.help_text": "e.g., 20240101. With binding: {{ date.ago(30, format='yyyymmdd') }}",
426
436
  "fields.OverseasStockHistoricalDataNode.symbol": "Enter the symbol code to query",
@@ -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,9 +1044,22 @@
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",
1062
+ "enums.interval.10m": "10 Minutes",
1033
1063
  "enums.interval.15m": "15 Minutes",
1034
1064
  "enums.interval.1M": "1 Month",
1035
1065
  "enums.interval.1Y": "1 year",
@@ -1040,6 +1070,7 @@
1040
1070
  "enums.interval.1m": "1 Minute",
1041
1071
  "enums.interval.1w": "1 Week",
1042
1072
  "enums.interval.5m": "5 Minutes",
1073
+ "enums.interval.60m": "60 Minutes",
1043
1074
  "enums.operator.all": "All Match (AND) - Every condition must pass",
1044
1075
  "enums.operator.any": "Any Match (OR) - At least one must pass",
1045
1076
  "enums.operator.at_least": "At Least N - threshold or more must pass",
@@ -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.",
@@ -140,7 +144,7 @@
140
144
  "nodes.OverseasStockBrokerNode.name": "해외주식 브로커",
141
145
  "nodes.OverseasStockCancelOrderNode.description": "미국 주식 미체결 주문을 원래 주문 ID로 취소합니다. OverseasStockOpenOrdersNode 또는 OverseasStockRealOrderEventNode에서 original_order_id를 받아야 합니다. 출력: 취소 결과, 취소된 주문 ID. 최소 5초 간격 제한 적용. 일반적인 연결: StockOpenOrdersNode → StockCancelOrderNode 또는 StockRealOrderEventNode → StockCancelOrderNode.",
142
146
  "nodes.OverseasStockCancelOrderNode.name": "해외주식 취소주문",
143
- "nodes.OverseasStockHistoricalDataNode.description": "지정 기간의 해외주식 과거 OHLCV(시가, 고가, 저가, 종가, 거래량) 차트 데이터를 조회합니다. LS g3204로 일봉·주봉·월봉·연봉을 조회합니다. 분봉·시간봉(g3203)은 지원하지 않습니다. 수정주가(주식 분할/배당 반영) 활성화 권장(백테스트용). 이전 노드가 여러 종목을 출력하면 자동 반복 실행. 상위 OverseasStockBrokerNode 연결 필수. 일반적인 연결: WatchlistNode → StockHistoricalDataNode → ConditionNode 또는 → BacktestEngineNode. 지원 거래소: NYSE, NASDAQ, AMEX. AI Agent 도구로 사용 가능.",
147
+ "nodes.OverseasStockHistoricalDataNode.description": "지정 기간의 해외주식 과거 OHLCV(시가, 고가, 저가, 종가, 거래량) 차트 데이터를 조회합니다. LS g3204로 일봉·주봉·월봉·연봉을, LS g3203으로 1·5·10·15·30·60분봉(최근 최대 500개 한 페이지)을 조회합니다. 수정주가(주식 분할/배당 반영) 활성화 권장(백테스트용). 이전 노드가 여러 종목을 출력하면 자동 반복 실행. 상위 OverseasStockBrokerNode 연결 필수. 일반적인 연결: WatchlistNode → StockHistoricalDataNode → ConditionNode 또는 → BacktestEngineNode. 지원 거래소: NYSE, NASDAQ, AMEX. AI Agent 도구로 사용 가능.",
144
148
  "nodes.OverseasStockHistoricalDataNode.name": "해외주식 과거데이터",
145
149
  "nodes.OverseasStockFundamentalNode.description": "LS증권 API로 해외주식 펀더멘털 재무 데이터를 조회합니다. PER, EPS, PBR, 시가총액, 배당수익률, 52주 고/저가 등 16개 지표를 제공합니다. 이전 노드가 여러 종목을 출력하면 자동 반복 실행. 상위 OverseasStockBrokerNode 연결 필수. 일반적인 연결: WatchlistNode → StockFundamentalNode → ConditionNode (가치 기반 스크리닝). 지원 거래소: NYSE, NASDAQ, AMEX. AI Agent 도구로 사용 가능.",
146
150
  "nodes.OverseasStockFundamentalNode.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",
@@ -420,7 +430,7 @@
420
430
  "fields.OverseasStockHistoricalDataNode.adjust.short": "수정주가 적용 여부",
421
431
  "fields.OverseasStockHistoricalDataNode.end_date": "조회 종료일 (YYYYMMDD)",
422
432
  "fields.OverseasStockHistoricalDataNode.end_date.help_text": "예: 20241231. 바인딩 시 {{ date.today(format='yyyymmdd') }} 사용 가능",
423
- "fields.OverseasStockHistoricalDataNode.interval": "LS g3204 봉 종류 (1d, 1w, 1M, 1Y). 분봉·시간봉 미지원",
433
+ "fields.OverseasStockHistoricalDataNode.interval": "봉 종류: 1d, 1w, 1M, 1Y (LS g3204) 또는 1m, 5m, 10m, 15m, 30m, 60m 분봉 (LS g3203, 최근 최대 500개)",
424
434
  "fields.OverseasStockHistoricalDataNode.start_date": "조회 시작일 (YYYYMMDD)",
425
435
  "fields.OverseasStockHistoricalDataNode.start_date.help_text": "예: 20240101. 바인딩 시 {{ date.ago(30, format='yyyymmdd') }} 사용 가능",
426
436
  "fields.OverseasStockHistoricalDataNode.symbol": "조회할 종목 코드를 입력하세요",
@@ -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,9 +1044,22 @@
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)",
1062
+ "enums.interval.10m": "10분",
1033
1063
  "enums.interval.15m": "15분",
1034
1064
  "enums.interval.1M": "1개월",
1035
1065
  "enums.interval.1Y": "1년",
@@ -1040,6 +1070,7 @@
1040
1070
  "enums.interval.1m": "1분",
1041
1071
  "enums.interval.1w": "1주",
1042
1072
  "enums.interval.5m": "5분",
1073
+ "enums.interval.60m": "60분",
1043
1074
  "enums.operator.all": "전체 만족 (AND) - 모든 조건 통과 필요",
1044
1075
  "enums.operator.any": "하나 이상 (OR) - 1개만 통과해도 OK",
1045
1076
  "enums.operator.at_least": "최소 N개 이상 - threshold 개수 이상 통과",
@@ -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",
@@ -65,9 +65,10 @@ class OverseasStockHistoricalDataNode(BaseNode):
65
65
  default="{{ date.today(format='yyyymmdd') }}",
66
66
  description="End date (YYYY-MM-DD or {{ date.today(format='yyyymmdd') }})",
67
67
  )
68
- interval: Literal["1d", "1w", "1M", "1Y"] = Field(
68
+ interval: Literal["1d", "1w", "1M", "1Y", "1m", "5m", "10m", "15m", "30m", "60m"] = Field(
69
69
  default="1d",
70
- description="LS g3204 interval: daily, weekly, monthly or yearly. Intraday is unsupported.",
70
+ description=("Bar size: 1d, 1w, 1M, 1Y read LS g3204; 1m, 5m, 10m, 15m, 30m, 60m read LS g3203 "
71
+ "minute bars (one page, newest up to 500 bars)."),
71
72
  )
72
73
  adjust: bool = Field(
73
74
  default=False,
@@ -81,6 +82,7 @@ class OverseasStockHistoricalDataNode(BaseNode):
81
82
  _usage: ClassVar[Dict[str, Any]] = {
82
83
  "when_to_use": [
83
84
  "Retrieve daily, weekly, monthly or yearly OHLCV history for a US-listed stock to compute technical indicators or run backtests",
85
+ "Retrieve 1/5/10/15/30/60-minute bars of a US-listed stock for an intraday indicator (one page of the newest bars)",
84
86
  "Feed time-series data into ConditionNode plugins (RSI, MACD, Bollinger, etc.) that require a `data` list of candles",
85
87
  "Use `{{ date.ago(N, format='yyyymmdd') }}` for start_date to get a rolling lookback window without hardcoding dates",
86
88
  ],
@@ -97,7 +99,9 @@ class OverseasStockHistoricalDataNode(BaseNode):
97
99
  }
98
100
  _features: ClassVar[List[str]] = [
99
101
  "Returns a list of OHLCV candles in `value.time_series`: [{date, open, high, low, close, volume}, ...]",
100
- "Supports intervals: 1d, 1w, 1M, 1Y through LS g3204; intraday history is unsupported",
102
+ "Supports intervals: 1d, 1w, 1M, 1Y through LS g3204 and 1m, 5m, 10m, 15m, 30m, 60m through LS g3203",
103
+ "A minute interval reads ONE g3203 page: the newest up to 500 bars at or before end_date within start_date..end_date; a longer range is not completed by paging",
104
+ "A minute bar's date is YYYYMMDDHHMMSS in the exchange's local time as LS labels it; pre-market, after-hours and overnight-session bars are included as LS returns them",
101
105
  "start_date / end_date accept YYYYMMDD strings or expression namespace calls: `{{ date.ago(30, format='yyyymmdd') }}`",
102
106
  "adjust=True applies split/dividend-adjusted prices for accurate long-term backtesting",
103
107
  "is_tool_enabled=True — AI Agent can fetch historical data autonomously for technical analysis",
@@ -156,12 +160,48 @@ class OverseasStockHistoricalDataNode(BaseNode):
156
160
  },
157
161
  "expected_output": "value port: {symbol, exchange, time_series: [{date, open, high, low, close, volume}, ...]}. RSI is computed from time_series.",
158
162
  },
163
+ {
164
+ "title": "15-minute bars for an intraday RSI",
165
+ "description": "Fetch the newest 15-minute bars of NVDA (LS g3203, one page of up to 500 bars) and compute RSI on them. Bar dates are YYYYMMDDHHMMSS in exchange local time and include extended-hours bars.",
166
+ "workflow_snippet": {
167
+ "id": "overseas_stock_minute_rsi",
168
+ "name": "Minute-bar RSI Signal",
169
+ "nodes": [
170
+ {"id": "start", "type": "StartNode"},
171
+ {"id": "broker", "type": "OverseasStockBrokerNode", "credential_id": "broker_cred", "paper_trading": False},
172
+ {"id": "split", "type": "SplitNode", "array": [{"symbol": "NVDA", "exchange": "NASDAQ"}]},
173
+ {"id": "historical", "type": "OverseasStockHistoricalDataNode", "symbol": "{{ nodes.split.item }}", "start_date": "{{ date.ago(5, format='yyyymmdd') }}", "end_date": "{{ date.today(format='yyyymmdd') }}", "interval": "15m"},
174
+ {"id": "condition", "type": "ConditionNode", "plugin": "RSI", "items": {"from": "{{ item.time_series }}", "extract": {"symbol": "{{ item.symbol }}", "exchange": "{{ item.exchange }}", "date": "{{ row.date }}", "close": "{{ row.close }}"}}, "fields": {"period": 14, "threshold": 30, "direction": "below"}},
175
+ {"id": "split_results", "type": "AggregateNode", "mode": "collect"},
176
+ ],
177
+ "edges": [
178
+ {"from": "start", "to": "broker"},
179
+ {"from": "broker", "to": "split"},
180
+ {"from": "split", "to": "historical"},
181
+ {"from": "broker", "to": "historical"},
182
+ {"from": "historical", "to": "condition"},
183
+ {"from": "condition", "to": "split_results"},
184
+ ],
185
+ "credentials": [
186
+ {
187
+ "credential_id": "broker_cred",
188
+ "type": "broker_ls_overseas_stock",
189
+ "data": [
190
+ {"key": "appkey", "value": "", "type": "password", "label": "App Key"},
191
+ {"key": "appsecret", "value": "", "type": "password", "label": "App Secret"},
192
+ ],
193
+ }
194
+ ],
195
+ },
196
+ "expected_output": "value port: {symbol, exchange, time_series: [{date: 'YYYYMMDDHHMMSS', open, high, low, close, volume}, ...]} oldest first. RSI is computed from the 15-minute closes.",
197
+ },
159
198
  ]
160
199
  _node_guide: ClassVar[Dict[str, Any]] = {
161
200
  "input_handling": (
162
201
  "The `symbol` field takes a single {exchange, symbol} dict — bind to `{{ nodes.split.item }}` in a per-symbol loop. "
163
202
  "start_date / end_date accept 'YYYYMMDD' strings or `{{ date.ago(N, format='yyyymmdd') }}` expressions. "
164
- "Supported intervals: 1d, 1w, 1M, 1Y through LS g3204. Intraday g3203 is not connected to this node."
203
+ "Supported intervals: 1d, 1w, 1M, 1Y through LS g3204; 1m, 5m, 10m, 15m, 30m, 60m through LS g3203 "
204
+ "(one page of the newest up to 500 bars, date = YYYYMMDDHHMMSS exchange local time)."
165
205
  ),
166
206
  "output_consumption": (
167
207
  "The `value` port emits a dict: {symbol, exchange, time_series: [{date, open, high, low, close, volume}, ...]}. "
@@ -177,9 +217,11 @@ class OverseasStockHistoricalDataNode(BaseNode):
177
217
  "pitfalls": [
178
218
  "`symbol: {{ item }}` / `{{ nodes.<split>.item }}` resolves only inside a per-symbol loop (auto-iterate over an upstream array, or a SplitNode branch). If the upstream array is empty for this run the node logs `No symbols to fetch` and returns an empty series — normal no-signal, not a defect. A `No symbols provided` WARNING means the symbol source is missing or the binding did not resolve",
179
219
  "Access time_series via `{{ nodes.historical.value.time_series }}` — the value port is a dict, not a plain list",
180
- "Intraday intervals (1m/5m/15m/1h) are unsupported; never substitute daily bars or invent a g3203 node connection",
220
+ "Minute intervals are 1m, 5m, 10m, 15m, 30m and 60m (not 1h or 1min); daily bars are never a substitute for an intraday strategy",
221
+ "Minute bars include every session LS returns: pre-market, after-hours and the overnight session from 20:00 local time of the previous day (a Sunday date can appear); the regular session is 09:30-16:00 exchange local time, so filter by the time part of `date` when a strategy needs the regular session only",
222
+ "`adjust` has no effect on minute intervals: LS g3203 has no adjusted-price option, minute bars are the prices as traded",
181
223
  "adjust=False (default) returns unadjusted prices; set True when comparing long-term price levels across splits",
182
- "The current executor requests one g3204 page; it does not expose response-time, continuation-completion or candle-finality evidence",
224
+ "The executor requests one g3204 or g3203 page; it does not expose response-time, continuation-completion or candle-finality evidence (the newest minute bar may still be forming)",
183
225
  ],
184
226
  }
185
227
 
@@ -300,12 +342,18 @@ class OverseasStockHistoricalDataNode(BaseNode):
300
342
  description="i18n:fields.OverseasStockHistoricalDataNode.interval",
301
343
  default="1d",
302
344
  required=True,
303
- enum_values=["1d", "1w", "1M", "1Y"],
345
+ enum_values=["1d", "1w", "1M", "1Y", "1m", "5m", "10m", "15m", "30m", "60m"],
304
346
  enum_labels={
305
347
  "1d": "i18n:enums.interval.1d",
306
348
  "1w": "i18n:enums.interval.1w",
307
349
  "1M": "i18n:enums.interval.1M",
308
- "1Y": "i18n:enums.interval.1Y"
350
+ "1Y": "i18n:enums.interval.1Y",
351
+ "1m": "i18n:enums.interval.1m",
352
+ "5m": "i18n:enums.interval.5m",
353
+ "10m": "i18n:enums.interval.10m",
354
+ "15m": "i18n:enums.interval.15m",
355
+ "30m": "i18n:enums.interval.30m",
356
+ "60m": "i18n:enums.interval.60m",
309
357
  },
310
358
  category=FieldCategory.PARAMETERS,
311
359
  expression_mode=ExpressionMode.FIXED_ONLY,
@@ -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 등 — 주문에 쓰는 값)"},