programgarden-core 1.19.0__tar.gz → 1.20.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.
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/PKG-INFO +1 -1
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/account_futures.py +2 -2
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/account_korea_stock.py +2 -2
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/account_stock.py +2 -2
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/base.py +224 -27
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/data_futures.py +9 -7
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/data_korea_stock.py +11 -6
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/data_stock.py +15 -10
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/realtime_futures.py +10 -7
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/realtime_korea_stock.py +10 -7
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/realtime_stock.py +10 -7
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/symbol.py +4 -2
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/symbol_futures.py +2 -1
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/symbol_korea_stock.py +2 -2
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/symbol_stock.py +2 -2
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/pyproject.toml +1 -1
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/README.md +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/__init__.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/bases/__init__.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/bases/client.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/bases/components.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/bases/listener.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/bases/mixins.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/bases/products.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/bases/sql.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/bases/storage.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/code_node.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/exceptions.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/expression/__init__.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/expression/evaluator.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/i18n/__init__.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/i18n/locales/en.json +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/i18n/locales/ko.json +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/i18n/translator.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/korea_alias.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/models/__init__.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/models/connection_rule.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/models/credential.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/models/edge.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/models/event.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/models/exchange.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/models/field_binding.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/models/job.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/models/order_diagnostics.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/models/plugin_resource.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/models/resilience.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/models/resource.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/models/validation.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/models/workflow.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/__init__.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/ai.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/backtest.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/backtest_futures.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/backtest_korea_stock.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/backtest_stock.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/broker.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/calculation.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/code.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/condition.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/data.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/display.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/event.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/fundamental_korea_stock.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/fundamental_stock.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/infra.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/market_external.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/market_status.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/open_orders_futures.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/open_orders_korea_stock.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/open_orders_stock.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/order.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/portfolio.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/risk.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/trigger.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/presets/__init__.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/presets/news_analyst.json +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/presets/risk_manager.json +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/presets/strategist.json +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/presets/technical_analyst.json +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/registry/__init__.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/registry/credential_registry.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/registry/node_registry.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/registry/plugin_registry.py +0 -0
- {programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/retry_executor.py +0 -0
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/account_futures.py
RENAMED
|
@@ -19,7 +19,7 @@ from programgarden_core.nodes.base import (
|
|
|
19
19
|
ProductScope,
|
|
20
20
|
BrokerProvider,
|
|
21
21
|
OVERSEAS_FUTURES_BALANCE_FIELDS,
|
|
22
|
-
|
|
22
|
+
OVERSEAS_FUTURES_POSITION_FIELDS,
|
|
23
23
|
SYMBOL_LIST_FIELDS,
|
|
24
24
|
)
|
|
25
25
|
|
|
@@ -171,7 +171,7 @@ class OverseasFuturesAccountNode(BaseNode):
|
|
|
171
171
|
_outputs: List[OutputPort] = [
|
|
172
172
|
OutputPort(name="held_symbols", type="symbol_list", description="i18n:ports.held_symbols", fields=SYMBOL_LIST_FIELDS),
|
|
173
173
|
OutputPort(name="balance", type="balance_data", description="i18n:ports.balance", fields=OVERSEAS_FUTURES_BALANCE_FIELDS),
|
|
174
|
-
OutputPort(name="positions", type="position_data", description="i18n:ports.positions", fields=
|
|
174
|
+
OutputPort(name="positions", type="position_data", description="i18n:ports.positions", fields=OVERSEAS_FUTURES_POSITION_FIELDS),
|
|
175
175
|
]
|
|
176
176
|
|
|
177
177
|
_version: ClassVar[str] = "1.0.0"
|
|
@@ -18,7 +18,7 @@ from programgarden_core.nodes.base import (
|
|
|
18
18
|
ProductScope,
|
|
19
19
|
BrokerProvider,
|
|
20
20
|
KOREA_STOCK_BALANCE_FIELDS,
|
|
21
|
-
|
|
21
|
+
KOREA_STOCK_POSITION_FIELDS,
|
|
22
22
|
SYMBOL_LIST_FIELDS,
|
|
23
23
|
)
|
|
24
24
|
|
|
@@ -170,7 +170,7 @@ class KoreaStockAccountNode(BaseNode):
|
|
|
170
170
|
_outputs: List[OutputPort] = [
|
|
171
171
|
OutputPort(name="held_symbols", type="symbol_list", description="i18n:ports.held_symbols", fields=SYMBOL_LIST_FIELDS),
|
|
172
172
|
OutputPort(name="balance", type="balance_data", description="i18n:ports.balance", fields=KOREA_STOCK_BALANCE_FIELDS),
|
|
173
|
-
OutputPort(name="positions", type="position_data", description="i18n:ports.positions", fields=
|
|
173
|
+
OutputPort(name="positions", type="position_data", description="i18n:ports.positions", fields=KOREA_STOCK_POSITION_FIELDS),
|
|
174
174
|
]
|
|
175
175
|
|
|
176
176
|
_version: ClassVar[str] = "1.0.0"
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/account_stock.py
RENAMED
|
@@ -19,7 +19,7 @@ from programgarden_core.nodes.base import (
|
|
|
19
19
|
ProductScope,
|
|
20
20
|
BrokerProvider,
|
|
21
21
|
OVERSEAS_STOCK_BALANCE_FIELDS,
|
|
22
|
-
|
|
22
|
+
OVERSEAS_STOCK_POSITION_FIELDS,
|
|
23
23
|
SYMBOL_LIST_FIELDS,
|
|
24
24
|
)
|
|
25
25
|
|
|
@@ -200,7 +200,7 @@ class OverseasStockAccountNode(BaseNode):
|
|
|
200
200
|
name="positions",
|
|
201
201
|
type="position_data",
|
|
202
202
|
description="i18n:ports.positions",
|
|
203
|
-
fields=
|
|
203
|
+
fields=OVERSEAS_STOCK_POSITION_FIELDS,
|
|
204
204
|
example=[
|
|
205
205
|
{"symbol": "AAPL", "exchange": "NASDAQ", "quantity": 10, "avg_price": 175.20, "pnl_rate": 6.99},
|
|
206
206
|
{"symbol": "TSLA", "exchange": "NASDAQ", "quantity": 5, "avg_price": 240.00, "pnl_rate": -2.50},
|
|
@@ -112,11 +112,81 @@ class OutputPort(BaseModel):
|
|
|
112
112
|
|
|
113
113
|
|
|
114
114
|
# === OutputPort.fields 공통 상수 ===
|
|
115
|
+
#
|
|
116
|
+
# 🔴 **상수 공유는 노드가 같은 키를 내보낼 때만 한다.**
|
|
117
|
+
# resolver 는 이 선언으로 `nodes.<id>.<port>.<field>` 의 필드 존재를 **정적 검증**한다.
|
|
118
|
+
# 그래서 선언이 런타임과 어긋나면 검증이 양방향으로 다 틀린다:
|
|
119
|
+
# 실제 있는 필드를 바인딩 → INVALID_EXPRESSION_REF 로 **부당 거부** (동작하는 워크플로우를 막음)
|
|
120
|
+
# 실제 없는 필드를 바인딩 → **통과** 시킨 뒤 런타임에 조용히 None (표에 '-' 만 찍힘)
|
|
121
|
+
# 노드 하나를 맞추려고 공유 상수에 필드를 더하면 **다른 노드가 반대 방향으로 거짓말**한다.
|
|
122
|
+
# → 런타임 키가 다르면 **노드별 상수로 쪼갠다.** 증명은 `tests/test_output_schema_contract.py`
|
|
123
|
+
# (executor 의 런타임 dict 리터럴을 AST 로 뽑아 선언과 대조).
|
|
124
|
+
|
|
125
|
+
# WatchlistNode / SymbolFilterNode / ExclusionListNode / 계좌 노드의 held_symbols —
|
|
126
|
+
# 정말로 exchange+symbol 둘만 내보내는 포트 전용.
|
|
115
127
|
SYMBOL_LIST_FIELDS: List[Dict[str, str]] = [
|
|
116
128
|
{"name": "exchange", "type": "string", "description": "거래소 코드 (NASDAQ, NYSE, CME 등)"},
|
|
117
129
|
{"name": "symbol", "type": "string", "description": "종목코드"},
|
|
118
130
|
]
|
|
119
131
|
|
|
132
|
+
# ── ScreenerNode.symbols (조건 검색 결과) ──
|
|
133
|
+
# LS(g3101 enrich) 분기와 yfinance 분기가 **같은 키 집합**을 내보낸다.
|
|
134
|
+
SCREENER_SYMBOL_FIELDS: List[Dict[str, str]] = [
|
|
135
|
+
{"name": "exchange", "type": "string", "description": "거래소 코드"},
|
|
136
|
+
{"name": "symbol", "type": "string", "description": "종목코드"},
|
|
137
|
+
{"name": "name", "type": "string", "description": "종목명 (상류 종목 리스트가 줬거나 yfinance 조회로 채움)"},
|
|
138
|
+
{"name": "market", "type": "string", "description": "시장 구분 (상류가 준 값 통과 — 예: KOSPI/KOSDAQ)"},
|
|
139
|
+
{"name": "price", "type": "number", "description": "현재가 (필터 시점)"},
|
|
140
|
+
{"name": "market_cap", "type": "number", "description": "시가총액"},
|
|
141
|
+
{"name": "volume", "type": "number", "description": "거래량"},
|
|
142
|
+
{"name": "sector", "type": "string", "description": "섹터 (yfinance 분기에서만 채워짐 — LS 분기는 빈 문자열)"},
|
|
143
|
+
]
|
|
144
|
+
|
|
145
|
+
# ── MarketUniverseNode.symbols (지수 구성종목) ──
|
|
146
|
+
MARKET_UNIVERSE_SYMBOL_FIELDS: List[Dict[str, str]] = [
|
|
147
|
+
{"name": "exchange", "type": "string", "description": "거래소 코드"},
|
|
148
|
+
{"name": "symbol", "type": "string", "description": "종목코드"},
|
|
149
|
+
{"name": "name", "type": "string", "description": "종목명"},
|
|
150
|
+
]
|
|
151
|
+
|
|
152
|
+
# ── OverseasStockSymbolQueryNode.symbols (g3190 마스터) ──
|
|
153
|
+
OVERSEAS_STOCK_SYMBOL_QUERY_FIELDS: List[Dict[str, str]] = [
|
|
154
|
+
{"name": "exchange", "type": "string", "description": "거래소 이름 (NASDAQ, NYSE 등)"},
|
|
155
|
+
{"name": "exchange_code", "type": "string", "description": "LS 거래소 코드"},
|
|
156
|
+
{"name": "symbol", "type": "string", "description": "종목코드"},
|
|
157
|
+
{"name": "name", "type": "string", "description": "종목명 (한글 우선, 없으면 영문)"},
|
|
158
|
+
{"name": "isin", "type": "string", "description": "ISIN 코드"},
|
|
159
|
+
{"name": "price", "type": "number", "description": "전일 종가"},
|
|
160
|
+
{"name": "market_cap", "type": "number", "description": "시가총액"},
|
|
161
|
+
{"name": "shares_outstanding", "type": "number", "description": "상장 주식 수"},
|
|
162
|
+
{"name": "currency", "type": "string", "description": "통화 코드"},
|
|
163
|
+
{"name": "suspend", "type": "string", "description": "거래정지 여부 (Y/N)"},
|
|
164
|
+
{"name": "sellonly", "type": "string", "description": "매도전용 여부 (Y/N)"},
|
|
165
|
+
]
|
|
166
|
+
|
|
167
|
+
# ── KoreaStockSymbolQueryNode.symbols (t9945 마스터) ──
|
|
168
|
+
KOREA_STOCK_SYMBOL_QUERY_FIELDS: List[Dict[str, str]] = [
|
|
169
|
+
{"name": "exchange", "type": "string", "description": "거래소 코드 (항상 KRX)"},
|
|
170
|
+
{"name": "market", "type": "string", "description": "시장 구분 (KOSPI / KOSDAQ)"},
|
|
171
|
+
{"name": "symbol", "type": "string", "description": "종목코드 (6자리)"},
|
|
172
|
+
{"name": "name", "type": "string", "description": "종목명"},
|
|
173
|
+
{"name": "is_etf", "type": "boolean", "description": "ETF 여부"},
|
|
174
|
+
{"name": "product", "type": "string", "description": "상품 구분 (항상 korea_stock)"},
|
|
175
|
+
]
|
|
176
|
+
|
|
177
|
+
# ── OverseasFuturesSymbolQueryNode.symbols (o3101 마스터) ──
|
|
178
|
+
OVERSEAS_FUTURES_SYMBOL_QUERY_FIELDS: List[Dict[str, str]] = [
|
|
179
|
+
{"name": "exchange", "type": "string", "description": "거래소 코드 (CME, HKEX 등 — 주문에 쓰는 값)"},
|
|
180
|
+
{"name": "exchange_code", "type": "string", "description": "LS 거래소 코드 (exchange 와 동일)"},
|
|
181
|
+
{"name": "exchange_name", "type": "string", "description": "거래소 한글명 (표시용 — 주문에 쓰면 안 된다)"},
|
|
182
|
+
{"name": "symbol", "type": "string", "description": "종목코드 (월물 포함)"},
|
|
183
|
+
{"name": "name", "type": "string", "description": "종목명"},
|
|
184
|
+
{"name": "base_product", "type": "string", "description": "기초상품 코드 (예: ES)"},
|
|
185
|
+
{"name": "base_product_name", "type": "string", "description": "기초상품명"},
|
|
186
|
+
{"name": "currency", "type": "string", "description": "통화 코드"},
|
|
187
|
+
{"name": "contract_month", "type": "string", "description": "월물 (YYYYMM)"},
|
|
188
|
+
]
|
|
189
|
+
|
|
120
190
|
# ── Partial-failure metadata (internal) ──
|
|
121
191
|
# Balance dicts may include these underscore-prefixed keys when the
|
|
122
192
|
# upstream API call partially fails. Consumers (PositionSizingNode,
|
|
@@ -187,16 +257,22 @@ KOREA_STOCK_REAL_BALANCE_FIELDS: List[Dict[str, str]] = [
|
|
|
187
257
|
]
|
|
188
258
|
|
|
189
259
|
# ── 국내주식 시세 전용 (t1102 기반) ──
|
|
260
|
+
# 런타임 정본: executor.py `MarketDataNodeExecutor._fetch_korea_stock`
|
|
261
|
+
# (해외와 같은 이름 규칙을 쓴다 — 예전 선언의 current_price/open_price/market_cap 은 런타임에 없었다.)
|
|
190
262
|
KOREA_STOCK_PRICE_DATA_FIELDS: List[Dict[str, str]] = [
|
|
191
263
|
{"name": "symbol", "type": "string", "description": "종목코드 (6자리)"},
|
|
264
|
+
{"name": "exchange", "type": "string", "description": "거래소 코드 (KRX)"},
|
|
192
265
|
{"name": "name", "type": "string", "description": "종목명"},
|
|
193
|
-
{"name": "
|
|
266
|
+
{"name": "price", "type": "number", "description": "현재가 (원)"},
|
|
267
|
+
{"name": "change", "type": "number", "description": "전일대비 (하락이면 음수)"},
|
|
268
|
+
{"name": "change_pct", "type": "number", "description": "등락률 (%)"},
|
|
194
269
|
{"name": "volume", "type": "number", "description": "거래량"},
|
|
195
|
-
{"name": "
|
|
196
|
-
{"name": "
|
|
197
|
-
{"name": "
|
|
198
|
-
{"name": "
|
|
199
|
-
{"name": "
|
|
270
|
+
{"name": "open", "type": "number", "description": "시가"},
|
|
271
|
+
{"name": "high", "type": "number", "description": "고가"},
|
|
272
|
+
{"name": "low", "type": "number", "description": "저가"},
|
|
273
|
+
{"name": "close", "type": "number", "description": "종가 (현재가와 동일)"},
|
|
274
|
+
{"name": "per", "type": "number", "description": "PER"},
|
|
275
|
+
{"name": "pbr", "type": "number", "description": "PBR"},
|
|
200
276
|
]
|
|
201
277
|
|
|
202
278
|
# ── 국내주식 펀더멘털 전용 ──
|
|
@@ -216,14 +292,114 @@ KOREA_STOCK_FUNDAMENTAL_FIELDS: List[Dict[str, str]] = [
|
|
|
216
292
|
{"name": "industry", "type": "string", "description": "업종명"},
|
|
217
293
|
]
|
|
218
294
|
|
|
219
|
-
|
|
295
|
+
# ── 보유 포지션 (positions 포트) ──
|
|
296
|
+
# 🔴 옛 공유 상수 `POSITION_FIELDS` 는 `pnl` / `pnl_percent` 를 선언했으나 **런타임에 그런 키는 없다**
|
|
297
|
+
# (실제는 `pnl_amount` / `pnl_rate`). 챗봇이 카탈로그를 보고 `pnl` 을 바인딩하면 정적 검증은
|
|
298
|
+
# 통과하고 런타임엔 조용히 None 이 됐다. 상품별로 키가 다르므로 노드별로 쪼갠다.
|
|
299
|
+
|
|
300
|
+
# 해외주식 REST 계좌 (COSOQ00201 block4)
|
|
301
|
+
OVERSEAS_STOCK_POSITION_FIELDS: List[Dict[str, str]] = [
|
|
220
302
|
{"name": "exchange", "type": "string", "description": "거래소 코드"},
|
|
221
303
|
{"name": "symbol", "type": "string", "description": "종목코드"},
|
|
304
|
+
{"name": "name", "type": "string", "description": "종목명"},
|
|
305
|
+
{"name": "qty", "type": "number", "description": "보유 수량"},
|
|
306
|
+
{"name": "quantity", "type": "number", "description": "보유 수량 (주문 노드 호환 별칭)"},
|
|
307
|
+
{"name": "direction", "type": "string", "description": "포지션 방향 (주식은 항상 long)"},
|
|
308
|
+
{"name": "close_side", "type": "string", "description": "청산 주문 방향 (주식은 항상 sell)"},
|
|
309
|
+
{"name": "avg_price", "type": "number", "description": "평균 매입가"},
|
|
310
|
+
{"name": "current_price", "type": "number", "description": "현재가"},
|
|
311
|
+
{"name": "pnl_amount", "type": "number", "description": "평가 손익 (금액)"},
|
|
312
|
+
{"name": "pnl_rate", "type": "number", "description": "수익률 (%)"},
|
|
313
|
+
{"name": "eval_amount", "type": "number", "description": "평가 금액"},
|
|
314
|
+
{"name": "purchase_amount", "type": "number", "description": "매입 금액"},
|
|
315
|
+
{"name": "currency", "type": "string", "description": "통화 코드"},
|
|
316
|
+
{"name": "market", "type": "string", "description": "시장 구분명"},
|
|
317
|
+
]
|
|
318
|
+
|
|
319
|
+
# 국내주식 REST 계좌 (t0424)
|
|
320
|
+
KOREA_STOCK_POSITION_FIELDS: List[Dict[str, str]] = [
|
|
321
|
+
{"name": "exchange", "type": "string", "description": "거래소 코드 (항상 KRX)"},
|
|
322
|
+
{"name": "symbol", "type": "string", "description": "종목코드"},
|
|
323
|
+
{"name": "name", "type": "string", "description": "종목명"},
|
|
222
324
|
{"name": "quantity", "type": "number", "description": "보유 수량"},
|
|
325
|
+
{"name": "price", "type": "number", "description": "현재가 (주문 노드 호환 별칭)"},
|
|
223
326
|
{"name": "avg_price", "type": "number", "description": "평균 매입가"},
|
|
224
327
|
{"name": "current_price", "type": "number", "description": "현재가"},
|
|
225
|
-
{"name": "
|
|
226
|
-
{"name": "
|
|
328
|
+
{"name": "pnl_amount", "type": "number", "description": "평가 손익 (금액)"},
|
|
329
|
+
{"name": "pnl_rate", "type": "number", "description": "수익률 (%)"},
|
|
330
|
+
{"name": "sellable_qty", "type": "number", "description": "매도 가능 수량"},
|
|
331
|
+
{"name": "eval_amount", "type": "number", "description": "평가 금액"},
|
|
332
|
+
{"name": "product", "type": "string", "description": "상품 구분 (항상 korea_stock)"},
|
|
333
|
+
]
|
|
334
|
+
|
|
335
|
+
# 해외선물 REST 계좌 (CIDBQ01500 block2)
|
|
336
|
+
# 주의: 이 TR 응답에는 수익률(pnl_rate)이 없다 — 손익 금액(pnl_amount)만 온다.
|
|
337
|
+
OVERSEAS_FUTURES_POSITION_FIELDS: List[Dict[str, str]] = [
|
|
338
|
+
{"name": "exchange", "type": "string", "description": "거래소 코드"},
|
|
339
|
+
{"name": "symbol", "type": "string", "description": "종목코드 (월물 포함)"},
|
|
340
|
+
{"name": "name", "type": "string", "description": "종목명"},
|
|
341
|
+
{"name": "direction", "type": "string", "description": "포지션 방향 (long / short)"},
|
|
342
|
+
{"name": "close_side", "type": "string", "description": "청산 주문 방향 (sell / buy)"},
|
|
343
|
+
{"name": "quantity", "type": "number", "description": "보유 계약 수"},
|
|
344
|
+
{"name": "price", "type": "number", "description": "현재가 (주문 노드 호환 별칭)"},
|
|
345
|
+
{"name": "entry_price", "type": "number", "description": "진입 가격"},
|
|
346
|
+
{"name": "current_price", "type": "number", "description": "현재가"},
|
|
347
|
+
{"name": "pnl_amount", "type": "number", "description": "평가 손익 (금액)"},
|
|
348
|
+
{"name": "currency", "type": "string", "description": "통화 코드"},
|
|
349
|
+
]
|
|
350
|
+
|
|
351
|
+
# ── 실시간 계좌 포지션 (RealAccountNode.positions) ──
|
|
352
|
+
# 실시간 노드는 두 갈래로 positions 를 내보낸다: ① REST 스냅샷 직렬화 ② WebSocket tracker.
|
|
353
|
+
# 둘의 키가 다르면 **같은 포트인데 순간마다 다른 필드**가 나온다 → 두 갈래를 같은 키로 통일했다.
|
|
354
|
+
OVERSEAS_STOCK_REAL_POSITION_FIELDS: List[Dict[str, str]] = [
|
|
355
|
+
{"name": "exchange", "type": "string", "description": "거래소 코드"},
|
|
356
|
+
{"name": "market_code", "type": "string", "description": "LS 시장 코드"},
|
|
357
|
+
{"name": "symbol", "type": "string", "description": "종목코드"},
|
|
358
|
+
{"name": "name", "type": "string", "description": "종목명"},
|
|
359
|
+
{"name": "qty", "type": "number", "description": "보유 수량"},
|
|
360
|
+
{"name": "quantity", "type": "number", "description": "보유 수량 (주문 노드 호환 별칭)"},
|
|
361
|
+
{"name": "price", "type": "number", "description": "현재가 (주문 노드 호환 별칭)"},
|
|
362
|
+
{"name": "avg_price", "type": "number", "description": "평균 매입가"},
|
|
363
|
+
{"name": "current_price", "type": "number", "description": "현재가"},
|
|
364
|
+
{"name": "pnl_amount", "type": "number", "description": "평가 손익 (금액)"},
|
|
365
|
+
{"name": "pnl_rate", "type": "number", "description": "수익률 (%)"},
|
|
366
|
+
{"name": "eval_amount", "type": "number", "description": "평가 금액"},
|
|
367
|
+
{"name": "currency", "type": "string", "description": "통화 코드"},
|
|
368
|
+
{"name": "product", "type": "string", "description": "상품 구분 (항상 overseas_stock)"},
|
|
369
|
+
]
|
|
370
|
+
|
|
371
|
+
KOREA_STOCK_REAL_POSITION_FIELDS: List[Dict[str, str]] = [
|
|
372
|
+
{"name": "exchange", "type": "string", "description": "거래소 코드 (항상 KRX)"},
|
|
373
|
+
{"name": "market_code", "type": "string", "description": "시장 구분 코드"},
|
|
374
|
+
{"name": "symbol", "type": "string", "description": "종목코드"},
|
|
375
|
+
{"name": "name", "type": "string", "description": "종목명"},
|
|
376
|
+
{"name": "qty", "type": "number", "description": "보유 수량"},
|
|
377
|
+
{"name": "quantity", "type": "number", "description": "보유 수량 (주문 노드 호환 별칭)"},
|
|
378
|
+
{"name": "price", "type": "number", "description": "현재가 (주문 노드 호환 별칭)"},
|
|
379
|
+
{"name": "avg_price", "type": "number", "description": "평균 매입가"},
|
|
380
|
+
{"name": "current_price", "type": "number", "description": "현재가"},
|
|
381
|
+
{"name": "pnl_amount", "type": "number", "description": "평가 손익 (금액)"},
|
|
382
|
+
{"name": "pnl_rate", "type": "number", "description": "수익률 (%)"},
|
|
383
|
+
{"name": "eval_amount", "type": "number", "description": "평가 금액"},
|
|
384
|
+
{"name": "currency", "type": "string", "description": "통화 코드 (항상 KRW)"},
|
|
385
|
+
{"name": "product", "type": "string", "description": "상품 구분 (항상 korea_stock)"},
|
|
386
|
+
]
|
|
387
|
+
|
|
388
|
+
OVERSEAS_FUTURES_REAL_POSITION_FIELDS: List[Dict[str, str]] = [
|
|
389
|
+
{"name": "exchange", "type": "string", "description": "거래소 코드"},
|
|
390
|
+
{"name": "symbol", "type": "string", "description": "종목코드 (월물 포함)"},
|
|
391
|
+
{"name": "name", "type": "string", "description": "종목명"},
|
|
392
|
+
{"name": "direction", "type": "string", "description": "포지션 방향 (long / short)"},
|
|
393
|
+
{"name": "close_side", "type": "string", "description": "청산 주문 방향 (sell / buy)"},
|
|
394
|
+
{"name": "qty", "type": "number", "description": "보유 계약 수"},
|
|
395
|
+
{"name": "quantity", "type": "number", "description": "보유 계약 수 (주문 노드 호환 별칭)"},
|
|
396
|
+
{"name": "price", "type": "number", "description": "현재가 (주문 노드 호환 별칭)"},
|
|
397
|
+
{"name": "entry_price", "type": "number", "description": "진입 가격"},
|
|
398
|
+
{"name": "current_price", "type": "number", "description": "현재가"},
|
|
399
|
+
{"name": "pnl_amount", "type": "number", "description": "평가 손익 (금액)"},
|
|
400
|
+
{"name": "pnl_rate", "type": "number", "description": "수익률 (%)"},
|
|
401
|
+
{"name": "currency", "type": "string", "description": "통화 코드"},
|
|
402
|
+
{"name": "product", "type": "string", "description": "상품 구분 (항상 overseas_futures)"},
|
|
227
403
|
]
|
|
228
404
|
|
|
229
405
|
ORDER_RESULT_FIELDS: List[Dict[str, str]] = [
|
|
@@ -236,16 +412,44 @@ ORDER_RESULT_FIELDS: List[Dict[str, str]] = [
|
|
|
236
412
|
{"name": "status", "type": "string", "description": "주문 상태"},
|
|
237
413
|
]
|
|
238
414
|
|
|
415
|
+
# ⚠️ 이 선언은 **런타임이 실제로 내보내는 키와 정확히 같아야 한다.**
|
|
416
|
+
# resolver 가 이 이름들로 필드 존재를 정적 검증하므로, 어긋나면 두 방향으로 다 틀린다:
|
|
417
|
+
# 실제 있는 필드를 바인딩 → INVALID_EXPRESSION_REF 로 **거부**
|
|
418
|
+
# 실제 없는 필드를 바인딩 → **통과**시킨 뒤 런타임에 조용히 None
|
|
419
|
+
# (2026-07-13 실측: 선언이 current_price/change_percent 였으나 런타임은 price/change_pct 였다.)
|
|
420
|
+
# 런타임 정본: executor.py `MarketDataNodeExecutor._fetch_overseas_stock`
|
|
239
421
|
PRICE_DATA_FIELDS: List[Dict[str, str]] = [
|
|
240
|
-
{"name": "exchange", "type": "string", "description": "거래소 코드"},
|
|
241
422
|
{"name": "symbol", "type": "string", "description": "종목코드"},
|
|
242
|
-
{"name": "
|
|
423
|
+
{"name": "exchange", "type": "string", "description": "거래소 코드"},
|
|
424
|
+
{"name": "price", "type": "number", "description": "현재가"},
|
|
425
|
+
{"name": "change", "type": "number", "description": "전일대비 (하락이면 음수)"},
|
|
426
|
+
{"name": "change_pct", "type": "number", "description": "등락률 (%)"},
|
|
243
427
|
{"name": "volume", "type": "number", "description": "거래량"},
|
|
244
|
-
{"name": "
|
|
428
|
+
{"name": "open", "type": "number", "description": "시가"},
|
|
429
|
+
{"name": "high", "type": "number", "description": "고가"},
|
|
430
|
+
{"name": "low", "type": "number", "description": "저가"},
|
|
431
|
+
{"name": "close", "type": "number", "description": "종가 (현재가와 동일)"},
|
|
245
432
|
{"name": "per", "type": "number", "description": "PER (주가수익비율)"},
|
|
246
433
|
{"name": "eps", "type": "number", "description": "EPS (주당순이익)"},
|
|
247
434
|
]
|
|
248
435
|
|
|
436
|
+
# ── 해외선물 시세 전용 (o3105 기반) ──
|
|
437
|
+
# 해외주식과 모양이 다르다(symbol_name 있음 / per·eps 없음). 상수를 공유하면 드리프트가 난다.
|
|
438
|
+
# 런타임 정본: executor.py `MarketDataNodeExecutor._fetch_overseas_futures`
|
|
439
|
+
OVERSEAS_FUTURES_PRICE_DATA_FIELDS: List[Dict[str, str]] = [
|
|
440
|
+
{"name": "symbol", "type": "string", "description": "종목코드 (월물 심볼)"},
|
|
441
|
+
{"name": "exchange", "type": "string", "description": "거래소 코드"},
|
|
442
|
+
{"name": "symbol_name", "type": "string", "description": "종목명"},
|
|
443
|
+
{"name": "price", "type": "number", "description": "현재가"},
|
|
444
|
+
{"name": "change", "type": "number", "description": "전일대비 (하락이면 음수)"},
|
|
445
|
+
{"name": "change_pct", "type": "number", "description": "등락률 (%)"},
|
|
446
|
+
{"name": "volume", "type": "number", "description": "거래량"},
|
|
447
|
+
{"name": "open", "type": "number", "description": "시가"},
|
|
448
|
+
{"name": "high", "type": "number", "description": "고가"},
|
|
449
|
+
{"name": "low", "type": "number", "description": "저가"},
|
|
450
|
+
{"name": "close", "type": "number", "description": "종가 (현재가와 동일)"},
|
|
451
|
+
]
|
|
452
|
+
|
|
249
453
|
FUNDAMENTAL_DATA_FIELDS: List[Dict[str, str]] = [
|
|
250
454
|
{"name": "exchange", "type": "string", "description": "거래소 코드"},
|
|
251
455
|
{"name": "symbol", "type": "string", "description": "종목코드"},
|
|
@@ -324,26 +528,19 @@ ORDER_EVENT_FIELDS: List[Dict[str, str]] = [
|
|
|
324
528
|
{"name": "timestamp", "type": "string", "description": "이벤트 시각"},
|
|
325
529
|
]
|
|
326
530
|
|
|
531
|
+
# ── 실시간 시세 노드의 봉(bar) ──
|
|
532
|
+
# 🔴 실시간 노드의 `ohlcv_data` / `data` 는 **같은 객체**다 (`data` 는 별칭).
|
|
533
|
+
# 값의 모양은 `{"AAPL": [bar, ...]}` — 종목코드로 키를 잡은 dict 이고, bar 가 아래 필드다.
|
|
534
|
+
# 옛 선언은 `exchange` / `timestamp` 를 약속했지만 런타임 bar 에 그런 키는 없고(실제는 `date`),
|
|
535
|
+
# `data` 포트는 아예 `current_price` / `bid_price` / `ask_price` / `change_percent` 를 약속했는데
|
|
536
|
+
# **그 값을 만드는 코드(`_build_full_data`)는 아무도 호출하지 않는 죽은 코드였다.**
|
|
327
537
|
OHLCV_DATA_FIELDS: List[Dict[str, str]] = [
|
|
328
|
-
{"name": "
|
|
329
|
-
{"name": "symbol", "type": "string", "description": "종목코드"},
|
|
538
|
+
{"name": "date", "type": "string", "description": "봉 일자 (YYYYMMDD)"},
|
|
330
539
|
{"name": "open", "type": "number", "description": "시가"},
|
|
331
540
|
{"name": "high", "type": "number", "description": "고가"},
|
|
332
541
|
{"name": "low", "type": "number", "description": "저가"},
|
|
333
|
-
{"name": "close", "type": "number", "description": "종가"},
|
|
334
|
-
{"name": "volume", "type": "number", "description": "거래량"},
|
|
335
|
-
{"name": "timestamp", "type": "string", "description": "캔들 시각"},
|
|
336
|
-
]
|
|
337
|
-
|
|
338
|
-
MARKET_DATA_FULL_FIELDS: List[Dict[str, str]] = [
|
|
339
|
-
{"name": "exchange", "type": "string", "description": "거래소 코드"},
|
|
340
|
-
{"name": "symbol", "type": "string", "description": "종목코드"},
|
|
341
|
-
{"name": "current_price", "type": "number", "description": "현재가"},
|
|
342
|
-
{"name": "bid_price", "type": "number", "description": "매수호가 (해외주식 실시간에서는 미제공)"},
|
|
343
|
-
{"name": "ask_price", "type": "number", "description": "매도호가 (해외주식 실시간에서는 미제공)"},
|
|
542
|
+
{"name": "close", "type": "number", "description": "종가 (= 최근 체결가)"},
|
|
344
543
|
{"name": "volume", "type": "number", "description": "거래량"},
|
|
345
|
-
{"name": "change_percent", "type": "number", "description": "등락률 (%)"},
|
|
346
|
-
{"name": "timestamp", "type": "string", "description": "시세 시각"},
|
|
347
544
|
]
|
|
348
545
|
|
|
349
546
|
CONDITION_RESULT_FIELDS: List[Dict[str, str]] = [
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/data_futures.py
RENAMED
|
@@ -22,7 +22,7 @@ from programgarden_core.nodes.base import (
|
|
|
22
22
|
OutputPort,
|
|
23
23
|
ProductScope,
|
|
24
24
|
BrokerProvider,
|
|
25
|
-
|
|
25
|
+
OVERSEAS_FUTURES_PRICE_DATA_FIELDS,
|
|
26
26
|
)
|
|
27
27
|
|
|
28
28
|
|
|
@@ -74,7 +74,7 @@ class OverseasFuturesMarketDataNode(BaseNode):
|
|
|
74
74
|
],
|
|
75
75
|
}
|
|
76
76
|
_features: ClassVar[List[str]] = [
|
|
77
|
-
"Returns a single futures contract's snapshot:
|
|
77
|
+
"Returns a single futures contract's snapshot: symbol, exchange, symbol_name, price, change, change_pct, volume, open, high, low, close",
|
|
78
78
|
"Item-based execution: pair with SplitNode to query multiple contracts in sequence",
|
|
79
79
|
"is_tool_enabled=True — AI Agent can call this node to look up live futures prices autonomously",
|
|
80
80
|
"Supported exchanges: CME, EUREX, SGX, HKEX — symbol format includes contract month code (e.g., ESH26)",
|
|
@@ -121,7 +121,7 @@ class OverseasFuturesMarketDataNode(BaseNode):
|
|
|
121
121
|
}
|
|
122
122
|
],
|
|
123
123
|
},
|
|
124
|
-
"expected_output": "values port: array of {symbol, exchange,
|
|
124
|
+
"expected_output": "values port: array of {symbol, exchange, symbol_name, price, change, change_pct, volume, open, high, low, close}.",
|
|
125
125
|
},
|
|
126
126
|
{
|
|
127
127
|
"title": "Multi-contract scan — compare HKEX futures prices",
|
|
@@ -161,9 +161,9 @@ class OverseasFuturesMarketDataNode(BaseNode):
|
|
|
161
161
|
"Broker connection auto-injected from OverseasFuturesBrokerNode."
|
|
162
162
|
),
|
|
163
163
|
"output_consumption": (
|
|
164
|
-
"Consume the `values` port ONLY — an array of {symbol, exchange,
|
|
164
|
+
"Consume the `values` port ONLY — an array of {symbol, exchange, symbol_name, price, change, change_pct, volume, open, high, low, close}. "
|
|
165
165
|
"⚠️ The `value` (singular) port is NOT populated at runtime — the executor emits `values` only; "
|
|
166
|
-
"binding `{{ nodes.market.value }}` (or `.value.
|
|
166
|
+
"binding `{{ nodes.market.value }}` (or `.value.price`) silently resolves to None. "
|
|
167
167
|
"TableDisplayNode.data ← `{{ nodes.market.values }}`; PositionSizingNode.market_data ← `{{ nodes.market.values }}`."
|
|
168
168
|
),
|
|
169
169
|
"common_combinations": [
|
|
@@ -183,11 +183,13 @@ class OverseasFuturesMarketDataNode(BaseNode):
|
|
|
183
183
|
InputPort(name="trigger", type="signal", description="i18n:ports.trigger", required=False),
|
|
184
184
|
]
|
|
185
185
|
_outputs: List[OutputPort] = [
|
|
186
|
-
OutputPort(name="value", type="market_data", description="i18n:ports.market_data_value",
|
|
186
|
+
OutputPort(name="value", type="market_data", description="i18n:ports.market_data_value",
|
|
187
|
+
fields=OVERSEAS_FUTURES_PRICE_DATA_FIELDS),
|
|
187
188
|
OutputPort(
|
|
188
189
|
name="values",
|
|
189
190
|
type="array",
|
|
190
|
-
description="Array of per-contract market quotes — [{symbol, exchange,
|
|
191
|
+
description="Array of per-contract market quotes — [{symbol, exchange, price, change, change_pct, ...}, ...]",
|
|
192
|
+
fields=OVERSEAS_FUTURES_PRICE_DATA_FIELDS,
|
|
191
193
|
),
|
|
192
194
|
]
|
|
193
195
|
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/data_korea_stock.py
RENAMED
|
@@ -74,7 +74,7 @@ class KoreaStockMarketDataNode(BaseNode):
|
|
|
74
74
|
],
|
|
75
75
|
}
|
|
76
76
|
_features: ClassVar[List[str]] = [
|
|
77
|
-
"Returns a single domestic stock's snapshot:
|
|
77
|
+
"Returns a single domestic stock's snapshot: symbol, exchange, name, price, change, change_pct, volume, open, high, low, close, per, pbr",
|
|
78
78
|
"Symbol format is a 6-digit KRX code (e.g., '005930') — no exchange field required (domestic market only)",
|
|
79
79
|
"Item-based execution: pair with SplitNode to query multiple domestic stocks in sequence",
|
|
80
80
|
"is_tool_enabled=True — AI Agent can call this node to look up KRX stock prices autonomously",
|
|
@@ -121,7 +121,7 @@ class KoreaStockMarketDataNode(BaseNode):
|
|
|
121
121
|
}
|
|
122
122
|
],
|
|
123
123
|
},
|
|
124
|
-
"expected_output": "values port: array of {symbol,
|
|
124
|
+
"expected_output": "values port: array of {symbol, exchange, name, price, change, change_pct, volume, open, high, low, close, per, pbr} per domestic stock.",
|
|
125
125
|
},
|
|
126
126
|
{
|
|
127
127
|
"title": "Price lookup for domestic PositionSizingNode",
|
|
@@ -165,11 +165,11 @@ class KoreaStockMarketDataNode(BaseNode):
|
|
|
165
165
|
),
|
|
166
166
|
"output_consumption": (
|
|
167
167
|
"Consume the `values` port ONLY — an array of per-symbol snapshots "
|
|
168
|
-
"[{symbol,
|
|
168
|
+
"[{symbol, exchange, name, price, change, change_pct, volume, open, high, low, close, per, pbr}, ...]. "
|
|
169
169
|
"⚠️ The `value` (singular) port is NOT populated at runtime — the executor emits `values` only; "
|
|
170
|
-
"binding `{{ nodes.market.value }}` (or `.value.
|
|
170
|
+
"binding `{{ nodes.market.value }}` (or `.value.price`) silently resolves to None. "
|
|
171
171
|
"TableDisplayNode.data ← `{{ nodes.market.values }}`; PositionSizingNode.market_data ← `{{ nodes.market.values }}` "
|
|
172
|
-
"(the array carries each symbol's
|
|
172
|
+
"(the array carries each symbol's price, which PositionSizingNode resolves internally)."
|
|
173
173
|
),
|
|
174
174
|
"common_combinations": [
|
|
175
175
|
"KoreaStockMarketDataNode.values → TableDisplayNode.data (KRX price monitor)",
|
|
@@ -189,7 +189,12 @@ class KoreaStockMarketDataNode(BaseNode):
|
|
|
189
189
|
]
|
|
190
190
|
_outputs: List[OutputPort] = [
|
|
191
191
|
OutputPort(name="value", type="market_data", description="i18n:ports.market_data_value", fields=KOREA_STOCK_PRICE_DATA_FIELDS),
|
|
192
|
-
OutputPort(
|
|
192
|
+
OutputPort(
|
|
193
|
+
name="values",
|
|
194
|
+
type="array",
|
|
195
|
+
description="Array of per-symbol market quotes — [{symbol, exchange, name, price, change, change_pct, ...}, ...]",
|
|
196
|
+
fields=KOREA_STOCK_PRICE_DATA_FIELDS,
|
|
197
|
+
),
|
|
193
198
|
]
|
|
194
199
|
|
|
195
200
|
_version: ClassVar[str] = "1.0.0"
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/data_stock.py
RENAMED
|
@@ -74,7 +74,7 @@ class OverseasStockMarketDataNode(BaseNode):
|
|
|
74
74
|
],
|
|
75
75
|
}
|
|
76
76
|
_features: ClassVar[List[str]] = [
|
|
77
|
-
"Returns a single symbol's snapshot:
|
|
77
|
+
"Returns a single symbol's snapshot: symbol, exchange, price, change, change_pct, volume, open, high, low, close, per, eps",
|
|
78
78
|
"Item-based execution: receives one {exchange, symbol} dict per call and emits one value dict — pair with SplitNode for multi-symbol queries",
|
|
79
79
|
"is_tool_enabled=True — AI Agent can call this node to look up live prices autonomously",
|
|
80
80
|
"Broker connection is auto-injected via DAG traversal — no explicit binding needed",
|
|
@@ -121,7 +121,7 @@ class OverseasStockMarketDataNode(BaseNode):
|
|
|
121
121
|
}
|
|
122
122
|
],
|
|
123
123
|
},
|
|
124
|
-
"expected_output": "values port: array of {symbol, exchange,
|
|
124
|
+
"expected_output": "values port: array of {symbol, exchange, price, change, change_pct, volume, open, high, low, close, per, eps} for each symbol.",
|
|
125
125
|
},
|
|
126
126
|
{
|
|
127
127
|
"title": "Price lookup feeding PositionSizingNode",
|
|
@@ -164,12 +164,11 @@ class OverseasStockMarketDataNode(BaseNode):
|
|
|
164
164
|
"The node auto-receives the broker connection via DAG traversal from OverseasStockBrokerNode."
|
|
165
165
|
),
|
|
166
166
|
"output_consumption": (
|
|
167
|
-
"Consume the `values` port ONLY — an array of {symbol, exchange,
|
|
168
|
-
"bid, ask, per, eps, 52w_high, 52w_low}. "
|
|
167
|
+
"Consume the `values` port ONLY — an array of {symbol, exchange, price, change, change_pct, volume, open, high, low, close, per, eps}. "
|
|
169
168
|
"⚠️ The `value` (singular) port is NOT populated at runtime — the executor emits `values` only; "
|
|
170
|
-
"binding `{{ nodes.market.value }}` (or `.value.
|
|
169
|
+
"binding `{{ nodes.market.value }}` (or `.value.price`) silently resolves to None. "
|
|
171
170
|
"TableDisplayNode.data ← `{{ nodes.market.values }}`; PositionSizingNode.market_data ← `{{ nodes.market.values }}` "
|
|
172
|
-
"(the array carries each symbol's
|
|
171
|
+
"(the array carries each symbol's price, resolved internally)."
|
|
173
172
|
),
|
|
174
173
|
"common_combinations": [
|
|
175
174
|
"WatchlistNode/SymbolQueryNode → OverseasStockMarketDataNode.symbols (multi-symbol price fetch)",
|
|
@@ -194,11 +193,16 @@ class OverseasStockMarketDataNode(BaseNode):
|
|
|
194
193
|
description="i18n:ports.market_data_value",
|
|
195
194
|
fields=PRICE_DATA_FIELDS,
|
|
196
195
|
example={
|
|
197
|
-
"exchange": "NASDAQ",
|
|
198
196
|
"symbol": "AAPL",
|
|
199
|
-
"
|
|
197
|
+
"exchange": "NASDAQ",
|
|
198
|
+
"price": 187.45,
|
|
199
|
+
"change": -2.34,
|
|
200
|
+
"change_pct": -1.23,
|
|
200
201
|
"volume": 12_345_678,
|
|
201
|
-
"
|
|
202
|
+
"open": 189.10,
|
|
203
|
+
"high": 190.02,
|
|
204
|
+
"low": 186.90,
|
|
205
|
+
"close": 187.45,
|
|
202
206
|
"per": 28.5,
|
|
203
207
|
"eps": 6.57,
|
|
204
208
|
},
|
|
@@ -206,7 +210,8 @@ class OverseasStockMarketDataNode(BaseNode):
|
|
|
206
210
|
OutputPort(
|
|
207
211
|
name="values",
|
|
208
212
|
type="array",
|
|
209
|
-
description="Array of per-symbol market quotes — [{symbol, exchange,
|
|
213
|
+
description="Array of per-symbol market quotes — [{symbol, exchange, price, change, change_pct, ...}, ...]",
|
|
214
|
+
fields=PRICE_DATA_FIELDS,
|
|
210
215
|
),
|
|
211
216
|
]
|
|
212
217
|
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/realtime_futures.py
RENAMED
|
@@ -21,11 +21,10 @@ from programgarden_core.nodes.base import (
|
|
|
21
21
|
ProductScope,
|
|
22
22
|
BrokerProvider,
|
|
23
23
|
OVERSEAS_FUTURES_REAL_BALANCE_FIELDS,
|
|
24
|
-
MARKET_DATA_FULL_FIELDS,
|
|
25
24
|
OHLCV_DATA_FIELDS,
|
|
26
25
|
ORDER_EVENT_FIELDS,
|
|
27
26
|
ORDER_LIST_FIELDS,
|
|
28
|
-
|
|
27
|
+
OVERSEAS_FUTURES_REAL_POSITION_FIELDS,
|
|
29
28
|
SYMBOL_LIST_FIELDS,
|
|
30
29
|
PRICE_DATA_FIELDS,
|
|
31
30
|
)
|
|
@@ -65,7 +64,7 @@ class OverseasFuturesRealMarketDataNode(BaseNode):
|
|
|
65
64
|
],
|
|
66
65
|
}
|
|
67
66
|
_features: ClassVar[List[str]] = [
|
|
68
|
-
"Streams real-time trade events from LS Securities WebSocket — ohlcv_data
|
|
67
|
+
"Streams real-time trade events from LS Securities WebSocket — ohlcv_data 포트가 집계된 봉을 내보낸다 (data 포트는 같은 객체의 별칭)",
|
|
69
68
|
"stay_connected=True keeps the WebSocket subscription live between cycles (recommended for realtime strategies)",
|
|
70
69
|
"Supports CME, EUREX, SGX, HKEX contracts — symbol must include contract month code (e.g., ESH26)",
|
|
71
70
|
"Item-based execution: one subscription per node; use multiple nodes to watch multiple contracts",
|
|
@@ -179,8 +178,11 @@ class OverseasFuturesRealMarketDataNode(BaseNode):
|
|
|
179
178
|
"Use OverseasFuturesBrokerNode as the upstream broker."
|
|
180
179
|
),
|
|
181
180
|
"output_consumption": (
|
|
182
|
-
"
|
|
183
|
-
"
|
|
181
|
+
"`ohlcv_data` 와 `data` 는 **같은 객체**다 — `data` 는 별칭이다. "
|
|
182
|
+
"(예전 문서는 `data` 가 bid/ask 를 담은 raw tick dict 이라고 했지만, 그 값을 만드는 코드는 "
|
|
183
|
+
"아무도 호출하지 않는 죽은 코드였다. 런타임에 bid/ask/current_price/change_percent 는 없다.) "
|
|
184
|
+
"값의 모양: {\"AAPL\": [{date, open, high, low, close, volume}, ...]} — 종목코드로 키를 잡은 dict 이고, "
|
|
185
|
+
"봉 한 줄에는 exchange/symbol/timestamp 가 없다. "
|
|
184
186
|
"ALWAYS insert ThrottleNode before any order or AI node downstream."
|
|
185
187
|
),
|
|
186
188
|
"common_combinations": [
|
|
@@ -210,7 +212,8 @@ class OverseasFuturesRealMarketDataNode(BaseNode):
|
|
|
210
212
|
]
|
|
211
213
|
_outputs: List[OutputPort] = [
|
|
212
214
|
OutputPort(name="ohlcv_data", type="ohlcv_data", description="i18n:ports.ohlcv_data", fields=OHLCV_DATA_FIELDS),
|
|
213
|
-
OutputPort(name="data", type="
|
|
215
|
+
OutputPort(name="data", type="ohlcv_data", description="i18n:ports.market_data_full", fields=OHLCV_DATA_FIELDS),
|
|
216
|
+
OutputPort(name="symbols", type="symbol_list", description="i18n:ports.symbols", fields=SYMBOL_LIST_FIELDS),
|
|
214
217
|
]
|
|
215
218
|
|
|
216
219
|
_version: ClassVar[str] = "1.0.0"
|
|
@@ -401,7 +404,7 @@ class OverseasFuturesRealAccountNode(BaseNode):
|
|
|
401
404
|
OutputPort(name="held_symbols", type="symbol_list", description="i18n:ports.held_symbols", fields=SYMBOL_LIST_FIELDS),
|
|
402
405
|
OutputPort(name="balance", type="balance_data", description="i18n:ports.balance", fields=OVERSEAS_FUTURES_REAL_BALANCE_FIELDS),
|
|
403
406
|
OutputPort(name="open_orders", type="order_list", description="i18n:ports.open_orders", fields=ORDER_LIST_FIELDS),
|
|
404
|
-
OutputPort(name="positions", type="position_data", description="i18n:ports.positions", fields=
|
|
407
|
+
OutputPort(name="positions", type="position_data", description="i18n:ports.positions", fields=OVERSEAS_FUTURES_REAL_POSITION_FIELDS),
|
|
405
408
|
]
|
|
406
409
|
|
|
407
410
|
_version: ClassVar[str] = "1.0.0"
|
|
@@ -21,11 +21,10 @@ from programgarden_core.nodes.base import (
|
|
|
21
21
|
ProductScope,
|
|
22
22
|
BrokerProvider,
|
|
23
23
|
KOREA_STOCK_REAL_BALANCE_FIELDS,
|
|
24
|
-
MARKET_DATA_FULL_FIELDS,
|
|
25
24
|
OHLCV_DATA_FIELDS,
|
|
26
25
|
ORDER_EVENT_FIELDS,
|
|
27
26
|
ORDER_LIST_FIELDS,
|
|
28
|
-
|
|
27
|
+
KOREA_STOCK_REAL_POSITION_FIELDS,
|
|
29
28
|
SYMBOL_LIST_FIELDS,
|
|
30
29
|
)
|
|
31
30
|
|
|
@@ -64,7 +63,7 @@ class KoreaStockRealMarketDataNode(BaseNode):
|
|
|
64
63
|
],
|
|
65
64
|
}
|
|
66
65
|
_features: ClassVar[List[str]] = [
|
|
67
|
-
"Streams real-time trade events from LS Securities WebSocket for KRX stocks — ohlcv_data
|
|
66
|
+
"Streams real-time trade events from LS Securities WebSocket for KRX stocks — ohlcv_data 포트가 집계된 봉을 내보낸다 (data 포트는 같은 객체의 별칭)",
|
|
68
67
|
"stay_connected=True keeps the WebSocket subscription live between cycles (recommended for realtime strategies)",
|
|
69
68
|
"Symbol format: 6-digit KRX code (e.g., '005930') without exchange field — domestic market implied",
|
|
70
69
|
"Item-based execution: one subscription per node; use multiple nodes to watch multiple domestic stocks",
|
|
@@ -178,8 +177,11 @@ class KoreaStockRealMarketDataNode(BaseNode):
|
|
|
178
177
|
"Use KoreaStockBrokerNode as the upstream broker."
|
|
179
178
|
),
|
|
180
179
|
"output_consumption": (
|
|
181
|
-
"
|
|
182
|
-
"
|
|
180
|
+
"`ohlcv_data` 와 `data` 는 **같은 객체**다 — `data` 는 별칭이다. "
|
|
181
|
+
"(예전 문서는 `data` 가 bid/ask 를 담은 raw tick dict 이라고 했지만, 그 값을 만드는 코드는 "
|
|
182
|
+
"아무도 호출하지 않는 죽은 코드였다. 런타임에 bid/ask/current_price/change_percent 는 없다.) "
|
|
183
|
+
"값의 모양: {\"AAPL\": [{date, open, high, low, close, volume}, ...]} — 종목코드로 키를 잡은 dict 이고, "
|
|
184
|
+
"봉 한 줄에는 exchange/symbol/timestamp 가 없다. "
|
|
183
185
|
"ALWAYS insert ThrottleNode before any order or AI node downstream."
|
|
184
186
|
),
|
|
185
187
|
"common_combinations": [
|
|
@@ -209,7 +211,8 @@ class KoreaStockRealMarketDataNode(BaseNode):
|
|
|
209
211
|
]
|
|
210
212
|
_outputs: List[OutputPort] = [
|
|
211
213
|
OutputPort(name="ohlcv_data", type="ohlcv_data", description="i18n:ports.ohlcv_data", fields=OHLCV_DATA_FIELDS),
|
|
212
|
-
OutputPort(name="data", type="
|
|
214
|
+
OutputPort(name="data", type="ohlcv_data", description="i18n:ports.market_data_full", fields=OHLCV_DATA_FIELDS),
|
|
215
|
+
OutputPort(name="symbols", type="symbol_list", description="i18n:ports.symbols", fields=SYMBOL_LIST_FIELDS),
|
|
213
216
|
]
|
|
214
217
|
|
|
215
218
|
_version: ClassVar[str] = "1.0.0"
|
|
@@ -404,7 +407,7 @@ class KoreaStockRealAccountNode(BaseNode):
|
|
|
404
407
|
OutputPort(name="held_symbols", type="symbol_list", description="i18n:ports.held_symbols", fields=SYMBOL_LIST_FIELDS),
|
|
405
408
|
OutputPort(name="balance", type="balance_data", description="i18n:ports.balance", fields=KOREA_STOCK_REAL_BALANCE_FIELDS),
|
|
406
409
|
OutputPort(name="open_orders", type="order_list", description="i18n:ports.open_orders", fields=ORDER_LIST_FIELDS),
|
|
407
|
-
OutputPort(name="positions", type="position_data", description="i18n:ports.positions", fields=
|
|
410
|
+
OutputPort(name="positions", type="position_data", description="i18n:ports.positions", fields=KOREA_STOCK_REAL_POSITION_FIELDS),
|
|
408
411
|
]
|
|
409
412
|
|
|
410
413
|
_version: ClassVar[str] = "1.0.0"
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/realtime_stock.py
RENAMED
|
@@ -21,11 +21,10 @@ from programgarden_core.nodes.base import (
|
|
|
21
21
|
ProductScope,
|
|
22
22
|
BrokerProvider,
|
|
23
23
|
OVERSEAS_STOCK_REAL_BALANCE_FIELDS,
|
|
24
|
-
MARKET_DATA_FULL_FIELDS,
|
|
25
24
|
OHLCV_DATA_FIELDS,
|
|
26
25
|
ORDER_EVENT_FIELDS,
|
|
27
26
|
ORDER_LIST_FIELDS,
|
|
28
|
-
|
|
27
|
+
OVERSEAS_STOCK_REAL_POSITION_FIELDS,
|
|
29
28
|
SYMBOL_LIST_FIELDS,
|
|
30
29
|
PRICE_DATA_FIELDS,
|
|
31
30
|
)
|
|
@@ -66,7 +65,7 @@ class OverseasStockRealMarketDataNode(BaseNode):
|
|
|
66
65
|
],
|
|
67
66
|
}
|
|
68
67
|
_features: ClassVar[List[str]] = [
|
|
69
|
-
"Streams GSC (trade/tick) events from LS Securities WebSocket — ohlcv_data
|
|
68
|
+
"Streams GSC (trade/tick) events from LS Securities WebSocket — ohlcv_data 포트가 집계된 봉을 내보낸다 (data 포트는 같은 객체의 별칭)",
|
|
70
69
|
"stay_connected=True keeps the WebSocket subscription live between cycles (recommended for realtime strategies)",
|
|
71
70
|
"Item-based execution: one subscription per node; use multiple nodes or SplitNode to watch several symbols",
|
|
72
71
|
"Automatically re-subscribes after WebSocket reconnection events",
|
|
@@ -180,8 +179,11 @@ class OverseasStockRealMarketDataNode(BaseNode):
|
|
|
180
179
|
"Set stay_connected=True (default) to avoid reconnection overhead on every cycle."
|
|
181
180
|
),
|
|
182
181
|
"output_consumption": (
|
|
183
|
-
"
|
|
184
|
-
"
|
|
182
|
+
"`ohlcv_data` 와 `data` 는 **같은 객체**다 — `data` 는 별칭이다. "
|
|
183
|
+
"(예전 문서는 `data` 가 bid/ask 를 담은 raw tick dict 이라고 했지만, 그 값을 만드는 코드는 "
|
|
184
|
+
"아무도 호출하지 않는 죽은 코드였다. 런타임에 bid/ask/current_price/change_percent 는 없다.) "
|
|
185
|
+
"값의 모양: {\"AAPL\": [{date, open, high, low, close, volume}, ...]} — 종목코드로 키를 잡은 dict 이고, "
|
|
186
|
+
"봉 한 줄에는 exchange/symbol/timestamp 가 없다. "
|
|
185
187
|
"ALWAYS insert ThrottleNode before any order or AI node downstream."
|
|
186
188
|
),
|
|
187
189
|
"common_combinations": [
|
|
@@ -211,7 +213,8 @@ class OverseasStockRealMarketDataNode(BaseNode):
|
|
|
211
213
|
]
|
|
212
214
|
_outputs: List[OutputPort] = [
|
|
213
215
|
OutputPort(name="ohlcv_data", type="ohlcv_data", description="i18n:ports.ohlcv_data", fields=OHLCV_DATA_FIELDS),
|
|
214
|
-
OutputPort(name="data", type="
|
|
216
|
+
OutputPort(name="data", type="ohlcv_data", description="i18n:ports.market_data_full", fields=OHLCV_DATA_FIELDS),
|
|
217
|
+
OutputPort(name="symbols", type="symbol_list", description="i18n:ports.symbols", fields=SYMBOL_LIST_FIELDS),
|
|
215
218
|
]
|
|
216
219
|
|
|
217
220
|
_version: ClassVar[str] = "1.0.0"
|
|
@@ -406,7 +409,7 @@ class OverseasStockRealAccountNode(BaseNode):
|
|
|
406
409
|
OutputPort(name="held_symbols", type="symbol_list", description="i18n:ports.held_symbols", fields=SYMBOL_LIST_FIELDS),
|
|
407
410
|
OutputPort(name="balance", type="balance_data", description="i18n:ports.balance", fields=OVERSEAS_STOCK_REAL_BALANCE_FIELDS),
|
|
408
411
|
OutputPort(name="open_orders", type="order_list", description="i18n:ports.open_orders", fields=ORDER_LIST_FIELDS),
|
|
409
|
-
OutputPort(name="positions", type="position_data", description="i18n:ports.positions", fields=
|
|
412
|
+
OutputPort(name="positions", type="position_data", description="i18n:ports.positions", fields=OVERSEAS_STOCK_REAL_POSITION_FIELDS),
|
|
410
413
|
]
|
|
411
414
|
|
|
412
415
|
_version: ClassVar[str] = "1.0.0"
|
|
@@ -24,6 +24,8 @@ from programgarden_core.nodes.base import (
|
|
|
24
24
|
InputPort,
|
|
25
25
|
OutputPort,
|
|
26
26
|
SYMBOL_LIST_FIELDS,
|
|
27
|
+
SCREENER_SYMBOL_FIELDS,
|
|
28
|
+
MARKET_UNIVERSE_SYMBOL_FIELDS,
|
|
27
29
|
)
|
|
28
30
|
from programgarden_core.models.exchange import SymbolEntry, ProductType
|
|
29
31
|
|
|
@@ -251,7 +253,7 @@ class MarketUniverseNode(BaseNode):
|
|
|
251
253
|
|
|
252
254
|
_inputs: List[InputPort] = []
|
|
253
255
|
_outputs: List[OutputPort] = [
|
|
254
|
-
OutputPort(name="symbols", type="symbol_list", description="i18n:ports.symbols", fields=
|
|
256
|
+
OutputPort(name="symbols", type="symbol_list", description="i18n:ports.symbols", fields=MARKET_UNIVERSE_SYMBOL_FIELDS),
|
|
255
257
|
OutputPort(name="count", type="integer", description="종목 수"),
|
|
256
258
|
]
|
|
257
259
|
|
|
@@ -453,7 +455,7 @@ class ScreenerNode(BaseNode):
|
|
|
453
455
|
),
|
|
454
456
|
]
|
|
455
457
|
_outputs: List[OutputPort] = [
|
|
456
|
-
OutputPort(name="symbols", type="symbol_list", description="i18n:ports.symbols", fields=
|
|
458
|
+
OutputPort(name="symbols", type="symbol_list", description="i18n:ports.symbols", fields=SCREENER_SYMBOL_FIELDS),
|
|
457
459
|
OutputPort(name="count", type="integer", description="결과 종목 수"),
|
|
458
460
|
]
|
|
459
461
|
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/symbol_futures.py
RENAMED
|
@@ -20,6 +20,7 @@ from programgarden_core.nodes.base import (
|
|
|
20
20
|
ProductScope,
|
|
21
21
|
BrokerProvider,
|
|
22
22
|
SYMBOL_LIST_FIELDS,
|
|
23
|
+
OVERSEAS_FUTURES_SYMBOL_QUERY_FIELDS,
|
|
23
24
|
)
|
|
24
25
|
|
|
25
26
|
|
|
@@ -182,7 +183,7 @@ class OverseasFuturesSymbolQueryNode(BaseNode):
|
|
|
182
183
|
|
|
183
184
|
_inputs: List[InputPort] = []
|
|
184
185
|
_outputs: List[OutputPort] = [
|
|
185
|
-
OutputPort(name="symbols", type="symbol_list", description="i18n:ports.symbols", fields=
|
|
186
|
+
OutputPort(name="symbols", type="symbol_list", description="i18n:ports.symbols", fields=OVERSEAS_FUTURES_SYMBOL_QUERY_FIELDS),
|
|
186
187
|
OutputPort(name="count", type="integer", description="Total symbol count"),
|
|
187
188
|
]
|
|
188
189
|
|
|
@@ -18,7 +18,7 @@ from programgarden_core.nodes.base import (
|
|
|
18
18
|
OutputPort,
|
|
19
19
|
ProductScope,
|
|
20
20
|
BrokerProvider,
|
|
21
|
-
|
|
21
|
+
KOREA_STOCK_SYMBOL_QUERY_FIELDS,
|
|
22
22
|
)
|
|
23
23
|
|
|
24
24
|
|
|
@@ -169,7 +169,7 @@ class KoreaStockSymbolQueryNode(BaseNode):
|
|
|
169
169
|
|
|
170
170
|
_inputs: List[InputPort] = []
|
|
171
171
|
_outputs: List[OutputPort] = [
|
|
172
|
-
OutputPort(name="symbols", type="symbol_list", description="i18n:ports.symbols", fields=
|
|
172
|
+
OutputPort(name="symbols", type="symbol_list", description="i18n:ports.symbols", fields=KOREA_STOCK_SYMBOL_QUERY_FIELDS),
|
|
173
173
|
OutputPort(name="count", type="integer", description="Total symbol count"),
|
|
174
174
|
]
|
|
175
175
|
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/symbol_stock.py
RENAMED
|
@@ -18,7 +18,7 @@ from programgarden_core.nodes.base import (
|
|
|
18
18
|
OutputPort,
|
|
19
19
|
ProductScope,
|
|
20
20
|
BrokerProvider,
|
|
21
|
-
|
|
21
|
+
OVERSEAS_STOCK_SYMBOL_QUERY_FIELDS,
|
|
22
22
|
)
|
|
23
23
|
|
|
24
24
|
|
|
@@ -177,7 +177,7 @@ class OverseasStockSymbolQueryNode(BaseNode):
|
|
|
177
177
|
|
|
178
178
|
_inputs: List[InputPort] = []
|
|
179
179
|
_outputs: List[OutputPort] = [
|
|
180
|
-
OutputPort(name="symbols", type="symbol_list", description="i18n:ports.symbols", fields=
|
|
180
|
+
OutputPort(name="symbols", type="symbol_list", description="i18n:ports.symbols", fields=OVERSEAS_STOCK_SYMBOL_QUERY_FIELDS),
|
|
181
181
|
OutputPort(name="count", type="integer", description="Total symbol count"),
|
|
182
182
|
]
|
|
183
183
|
|
|
@@ -5,7 +5,7 @@ authors = [
|
|
|
5
5
|
homepage = "https://programgarden.com"
|
|
6
6
|
requires-python = ">=3.12"
|
|
7
7
|
name = "programgarden-core"
|
|
8
|
-
version = "1.
|
|
8
|
+
version = "1.20.0"
|
|
9
9
|
license = "AGPL-3.0-or-later"
|
|
10
10
|
description = "ProgramGarden Core - 노드 기반 DSL 핵심 타입 정의"
|
|
11
11
|
readme = "README.md"
|
|
File without changes
|
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/bases/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/bases/components.py
RENAMED
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/bases/listener.py
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/bases/products.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/expression/__init__.py
RENAMED
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/expression/evaluator.py
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/i18n/locales/en.json
RENAMED
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/i18n/locales/ko.json
RENAMED
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/i18n/translator.py
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/models/__init__.py
RENAMED
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/models/connection_rule.py
RENAMED
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/models/credential.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/models/exchange.py
RENAMED
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/models/field_binding.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/models/plugin_resource.py
RENAMED
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/models/resilience.py
RENAMED
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/models/resource.py
RENAMED
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/models/validation.py
RENAMED
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/models/workflow.py
RENAMED
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/backtest.py
RENAMED
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/backtest_futures.py
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/backtest_stock.py
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/calculation.py
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/condition.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/market_external.py
RENAMED
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/market_status.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/nodes/portfolio.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/presets/__init__.py
RENAMED
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/presets/news_analyst.json
RENAMED
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/presets/risk_manager.json
RENAMED
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/presets/strategist.json
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/registry/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/registry/node_registry.py
RENAMED
|
File without changes
|
|
File without changes
|
{programgarden_core-1.19.0 → programgarden_core-1.20.0}/programgarden_core/retry_executor.py
RENAMED
|
File without changes
|