> For the complete documentation index, see [llms.txt](https://programgarden.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://programgarden.gitbook.io/docs/nodes/node_reference.md).
# ì ì²´ ë
¸ë ë í¼ë°ì¤
ProgramGardenìì ì¬ì©í ì ìë 모ë ë
¸ëì ìì¸ ì¤ëª
ì
ëë¤. ê° ë
¸ëë ìí¬íë¡ì°ìì íëì **ë¸ë¡** ìí ì íë©°, ë¸ë¡ì ì°ê²°(ì£ì§)íì¬ ìë매매 ì ëµì ë§ëëë¤.
> **ë
¸ë ì**: 12ê° ì¹´í
ê³ ë¦¬, 73ê° ë
¸ë
>
> **í´ì¸ì£¼ì / í´ì¸ì 물 / êµë´ì£¼ì**: ëë¶ë¶ì ë
¸ëê° ìíë³ë¡ ë¶ë¦¬ëì´ ììµëë¤. ì를 ë¤ì´ `OverseasStockBrokerNode`(í´ì¸ì£¼ì), `OverseasFuturesBrokerNode`(í´ì¸ì 물), `KoreaStockBrokerNode`(êµë´ì£¼ì)ë ê°ì 기ë¥ì´ì§ë§ ìíì´ ë¤ë¦
ëë¤.
***
## 1. infra - ì¸íë¼/ì°ê²°
ìí¬íë¡ì°ì ììì , ì¦ê¶ì¬ ì°ê²°, ë°ì´í° íë¦ ì ì´ë¥¼ ë´ë¹íë ê¸°ë° ë
¸ëë¤ì
ëë¤.
### StartNode
ìí¬íë¡ì°ì **ì§ì
ì **ì
ëë¤. 모ë ìí¬íë¡ì°ì ë°ëì 1ê° ìì´ì¼ í©ëë¤. StartNode ìì´ë ìí¬íë¡ì°ê° ì¤íëì§ ììµëë¤.
```json
{
"id": "start",
"type": "StartNode"
}
```
**ì¶ë ¥**: `start` - ìí¬íë¡ì° ìì ì í¸
> **주ì**: StartNodeë ScheduleNodeì í¨ê» ì¬ì©íë©´ ì¤ì¼ì¤ì ë°ë¼ ë°ë³µ ì¤íë©ëë¤. StartNodeë§ ìì¼ë©´ 1í ì¤í í ì¢
ë£ë©ëë¤.
***
### BrokerNode (ì¦ê¶ì¬ ì°ê²°)
LSì¦ê¶ APIì ì°ê²°íë ë
¸ëì
ëë¤. **ì¦ê¶ì¬ ì°ê²°ì´ íìí 모ë ë
¸ë**(ê³ì¢ ì¡°í, ìì¸ ì¡°í, 주문 ë±)ë ì´ ë
¸ëê° ë¨¼ì ìì´ì¼ í©ëë¤.
ìí ì íì ë°ë¼ ë
¸ë íì
ì´ ë¤ë¦
ëë¤:
| ìí | ë
¸ë íì
| credential íì
| 모ìí¬ì |
| ---- | --------------------------- | ---------------------------- | ------------ |
| í´ì¸ì£¼ì | `OverseasStockBrokerNode` | `broker_ls_overseas_stock` | 미ì§ì (ì¤ì ë§ ê°ë¥) |
| í´ì¸ì 물 | `OverseasFuturesBrokerNode` | `broker_ls_overseas_futures` | ì§ì |
| êµë´ì£¼ì | `KoreaStockBrokerNode` | `broker_ls_korea_stock` | 미ì§ì (ì¤ì ë§ ê°ë¥) |
**í´ì¸ì£¼ì ì°ê²° (ì¤ì ì ì©):**
```json
{
"id": "broker",
"type": "OverseasStockBrokerNode",
"credential_id": "my-stock-cred",
"paper_trading": false
}
```
**í´ì¸ì 물 ì°ê²° (모ìí¬ì):**
```json
{
"id": "broker",
"type": "OverseasFuturesBrokerNode",
"credential_id": "my-futures-cred",
"paper_trading": true
}
```
**êµë´ì£¼ì ì°ê²°:**
```json
{
"id": "broker",
"type": "KoreaStockBrokerNode",
"credential_id": "my-kr-cred"
}
```
| íë | íì
| íì | ì¤ëª
|
| --------------- | ------- | :-: | ------------------------------------------------------------------------------------------------------------------ |
| `credential_id` | string | â
| credentials ì¹ì
ìì ì ìí ì¸ì¦ ID |
| `paper_trading` | boolean | â | 모ìí¬ì ì¬ë¶. **í´ì¸ì£¼ìì `false` ëª
ì íì** (기본ê°ì´ trueì¬ì ì¤ì ì°ê²°ì´ ì¤í¨). í´ì¸ì 물ì `true`ë¡ ëª¨ìí¬ì. êµë´ì£¼ìì 모ìí¬ì 미ì§ìì´ë¯ë¡ ë´ë¶ì ì¼ë¡ íì false ê°ì . |
**ì¶ë ¥**: `connection` - ì¦ê¶ì¬ ì°ê²° ê°ì²´
> **ìë ì ë¬**: BrokerNodeì `connection`ì íì ë
¸ë(ê³ì¢, ìì¸, 주문 ë±)ì ìëì¼ë¡ ì ë¬ë©ëë¤. ì£ì§ë¡ ì°ê²°ë§ í´ì£¼ë©´ ëê³ , `{{ nodes.broker.connection }}`ì²ë¼ ì§ì ë°ì¸ë©í íìê° ììµëë¤.
> **â ï¸ OverseasStockBrokerNodeë `paper_trading: false` íì**: Executorì `paper_trading` 기본ê°ì `true`ì
ëë¤. í´ì¸ì£¼ì ë
¸ëìì ì´ íë를 ìëµíë©´ 기본ê°(`true`)ì¼ë¡ ì²ë¦¬ëì§ë§, LSì¦ê¶ì í´ì¸ì£¼ì ì¤ê±°ëë§ ì ê³µíë¯ë¡ ì°ê²°ì´ ì¦ì ê±°ë¶ëê³ íì ë
¸ë(ìì¸Â·ê³ì¢Â·ì£¼ë¬¸ ì ë¶)ê° ì í ì¤ë¥ë¡ 깨ì§ëë¤. ë°ë¼ì **ì¤ê±°ë ì°ê²°ì ìí´ ë°ëì `paper_trading: false`를 ëª
ì**í´ì¼ í©ëë¤.
| ë
¸ë | `paper_trading` ê° | ì미 |
| --------------------------- | ----------------- | ---------------------------- |
| `OverseasStockBrokerNode` | `false` **íì ëª
ì** | ì¤ê±°ë ì°ê²° (모ìí¬ì 모ë ìì) |
| `OverseasFuturesBrokerNode` | `true` / `false` | `true` â 모ìí¬ì, `false` â ì¤ê±°ë |
| `KoreaStockBrokerNode` | (ì§ì ë¶ê°) | ë´ë¶ì ì¼ë¡ íì `false` ê°ì |
> **주ì - credential ì¤ì **: `credential_id`ê° credentials ì¹ì
ì IDì ì íí ì¼ì¹í´ì¼ í©ëë¤. ë¶ì¼ì¹íë©´ ì°ê²°ì ì¤í¨í©ëë¤.
***
### ThrottleNode
ì¤ìê° ë°ì´í°ì íë¦ì ì ì´íë **ìë ì¡°ì 기**ì
ëë¤. ì¤ìê° ë
¸ë(RealMarketDataNode, RealAccountNode ë±)ë ì´ë¹ ìì ë² ë°ì´í°ë¥¼ ë³´ë´ëë°, ì´ë¥¼ ë°ìì íì ë
¸ëê° ë무 ì주 ì¤íëì§ ìëë¡ ë§ìì¤ëë¤.
```json
{
"id": "throttle",
"type": "ThrottleNode",
"mode": "latest",
"interval_sec": 5,
"pass_first": true
}
```
| íë | íì
| ê¸°ë³¸ê° | ì¤ëª
|
| -------------- | ---------------------- | ---------- | ---------------------- |
| `mode` | `"skip"` \| `"latest"` | `"latest"` | 쿨ë¤ì´ ì¤ ë°ì´í° ì²ë¦¬ ë°©ì |
| `interval_sec` | number | `5` | ìµì ì¤í ê°ê²© (ì´), 0.1\~300 |
| `pass_first` | boolean | `true` | 첫 ë²ì§¸ ë°ì´í°ë¥¼ ì¦ì íµê³¼ìí¬ì§ ì¬ë¶ |
**모ë ì¤ëª
:**
| 모ë | ëì | ì¸ì ì°ëì? |
| -------- | -------------------------------------- | --------------------------- |
| `skip` | 쿨ë¤ì´ ì¤ ë¤ì´ì¤ë ë°ì´í°ë¥¼ ì ë¶ ë²ë¦¼ | ë¨ìí ì¤í ë¹ëë§ ì¤ì´ê³ ì¶ì ë |
| `latest` | 쿨ë¤ì´ ì¤ ìµì ë°ì´í°ë§ 기ìµí´ëê³ , 쿨ë¤ì´ ëëë©´ ê·¸ ë°ì´í°ë¡ ì¤í | íì ìµì ìí를 ë°ìí´ì¼ í ë **(ê¶ì¥)** |
**latest 모ë ëì ìì:**
```
ìê° â 0ì´ 1ì´ 2ì´ 3ì´ 4ì´ 5ì´ 6ì´
ë°ì´í° A B C D - E F
ê²°ê³¼ íµê³¼ ë기 ë기 ë기 Dì¤í íµê³¼
(쿨ë¤ì´ ëëë©´ ê°ì¥ ìµì ì¸ D ì¤í)
```
**íì ì¬ì© í¨í´:**
{% @mermaid/diagram content="flowchart LR
A\[RealAccountNode] -->|ë¹ë²í ì´ë²¤í¸| B\[ThrottleNode] -->|5ì´ë§ë¤| C\[ConditionNode] --> D\[OrderNode]" %}
> **ì¤ì**: ì¤ìê° ë
¸ë â 주문 ë
¸ë, ì¤ìê° ë
¸ë â AI ìì´ì í¸ë¥¼ **ì§ì ì°ê²°íë©´ ì°¨ë¨**ë©ëë¤. ë°ëì ThrottleNode를 ì¬ì´ì ë£ì´ì¼ í©ëë¤. ì´ë ì´ë¹ ìì ë²ì ì£¼ë¬¸ì´ ëê°ë ì¬ê³ 를 ë°©ì§í기 ìí ìì ì¥ì¹ì
ëë¤.
> **í**: `interval_sec`ì ë무 ì§§ê² ì¤ì íë©´ API í¸ì¶ì´ ê³¼ëí´ì ¸ ì¦ê¶ì¬ìì ì íë¹í ì ììµëë¤. 주문 ê´ë ¨ íë¦ììë ìµì 5ì´ ì´ìì ê¶ì¥í©ëë¤.
***
### SplitNode
리ì¤í¸(ë°°ì´) ë°ì´í°ë¥¼ ê°ë³ í목ì¼ë¡ **ë¶ë¦¬**íì¬ íëì© ì²ë¦¬í©ëë¤. ì를 ë¤ì´ ê´ì¬ì¢
목 3ê°ë¥¼ íëì© ë¶ë¦¬í´ì ê°ê° ì°¨í¸ ë°ì´í°ë¥¼ ì¡°íí ë ì¬ì©í©ëë¤.
```json
{
"id": "split",
"type": "SplitNode",
"parallel": false,
"continue_on_error": true
}
```
| íë | íì
| ê¸°ë³¸ê° | ì¤ëª
|
| ------------------- | ------- | ------- | -------------------------- |
| `parallel` | boolean | `false` | ë³ë ¬ ì¤í ì¬ë¶ (trueë©´ ëìì ì¤í) |
| `delay_ms` | number | `0` | í목 ê° ë기 ìê° (ë°ë¦¬ì´, 0\~60000) |
| `continue_on_error` | boolean | `true` | íëê° ìë¬ ëë ëë¨¸ì§ ê³ì ì²ë¦¬ |
**ì¶ë ¥:**
* `item` - íì¬ ì²ë¦¬ ì¤ì¸ í목
* `index` - íì¬ ìë² (0ë¶í° ìì)
* `total` - ì ì²´ í목 ì
**ì¬ì© ìì:**
{% @mermaid/diagram content="flowchart LR
A\["WatchlistNode
(AAPL, NVDA, TSM)"] -->|3ê° ì¢
목| B\["SplitNode
(1ê°ì©)"]
B -->|"1íì°¨: AAPL"| C\[HistoricalDataNode]
B -->|"2íì°¨: NVDA"| C
B -->|"3íì°¨: TSM"| C" %}
íì ë
¸ëìì íì¬ í목ì 참조í ëë `{{ item }}`ì ì¬ì©í©ëë¤:
```json
{
"id": "history",
"type": "OverseasStockHistoricalDataNode",
"symbol": "{{ item }}"
}
```
> **주ì - API í¸ì¶ ì í**: ì¢
ëª©ì´ ë§ì ë `parallel: true`ë¡ ì¤ì íë©´ ì¦ê¶ì¬ API를 ëìì ë§ì´ í¸ì¶íê² ëì´ ì íë¹í ì ììµëë¤. 10ê° ì´ìì ì¢
목ì ì²ë¦¬í ëë `parallel: false`ë¡ íê³ `delay_ms: 500` ì ë를 ê¶ì¥í©ëë¤.
> **í**: SplitNode ìì´ë ì´ì ë
¸ëê° ë°°ì´ì ì¶ë ¥íë©´ ë¤ì ë
¸ëê° ìëì¼ë¡ ë°ë³µ ì¤íë©ëë¤ (Auto-Iterate). SplitNodeì `parallel`, `delay_ms` ë± ì¸ë°í ì ì´ê° íìí ë ì¬ì©íì¸ì. ìì¸í ë´ì©ì [ìë ë°ë³µ ì²ë¦¬ ê°ì´ë](/docs/workflow/auto_iterate_guide.md)를 ì°¸ê³ íì¸ì.
***
### AggregateNode
SplitNodeì¼ë¡ ë¶ë¦¬ë 결과를 ë¤ì **íëë¡ ëª¨ì¼ë** ë
¸ëì
ëë¤. ì를 ë¤ì´ 3ê° ì¢
목ì RSI 결과를 모ìì ì¡°ê±´ì íµê³¼í ì¢
ëª©ë§ íí°ë§í ë ì¬ì©í©ëë¤.
```json
{
"id": "aggregate",
"type": "AggregateNode",
"mode": "collect"
}
```
| íë | íì
| ê¸°ë³¸ê° | ì¤ëª
|
| -------------- | ------ | ----------- | -------------------------------- |
| `mode` | string | `"collect"` | ì§ê³ ë°©ì |
| `filter_field` | string | `"passed"` | `filter` 모ëìì íí°ë§í íëëª
|
| `value_field` | string | `"value"` | `sum`/`avg`/`min`/`max`ìì ëì íëëª
|
**mode ìµì
:**
| 모ë | ì¤ëª
| ì¬ì© ìì |
| ---------------- | ------------------ | ---------------------- |
| `collect` | 모ë 결과를 ë°°ì´ë¡ 모ì | 3ê° ì¢
목ì ì°¨í¸ ë°ì´í°ë¥¼ íëì ë°°ì´ë¡ |
| `filter` | í¹ì íëê° trueì¸ ê²ë§ 모ì | RSI ì¡°ê±´ íµê³¼í ì¢
ëª©ë§ |
| `sum` | ì«ì í©ê³ | ì ì²´ í¬ì§ì
ê¸ì¡ í©ê³ |
| `avg` | ì«ì íê· | íê· ììµë¥ |
| `min` / `max` | ìµìê° / ìµëê° | ê°ì¥ ë®ì RSI ê° |
| `count` | ê°ì | ì¡°ê±´ íµê³¼í ì¢
목 ì |
| `first` / `last` | 첫 ë²ì§¸ / ë§ì§ë§ í목 | - |
**ì¶ë ¥:**
* `array` - ì§ê³ë ë°°ì´
* `value` - ì§ê³ë ë¨ì¼ ê° (sum, avg ë±)
* `count` - í목 ì
**ì íì ì¸ í¨í´ (Split â ì²ë¦¬ â Aggregate):**
{% @mermaid/diagram content="flowchart LR
A\["WatchlistNode
(3ì¢
목)"] --> B\["SplitNode
(ë¶ë¦¬)"] --> C\["HistoricalDataNode
(ê°ê° ì¡°í)"] --> D\["ConditionNode
(ê°ê° íê°)"] --> E\["AggregateNode
(ê²°ê³¼ ì·¨í©)"]" %}
***
### IfNode (ì¡°ê±´ ë¶ê¸°)
ì¡°ê±´ì íê°íì¬ **true/false ë ê°ëë¡ ì¤í íë¦ì ë¶ê¸°**íë ë
¸ëì
ëë¤. íë¡ê·¸ëë°ì `if-else`ì ê°ì ìí ì
ëë¤.
```json
{
"nodes": [
{"id": "account", "type": "OverseasStockAccountNode"},
{"id": "if1", "type": "IfNode",
"left": "{{ nodes.account.balance }}",
"operator": ">=",
"right": 1000000},
{"id": "order", "type": "OverseasStockNewOrderNode"},
{"id": "notify", "type": "FieldMappingNode"}
],
"edges": [
{"from": "account", "to": "if1"},
{"from": "if1", "to": "order", "from_port": "true"},
{"from": "if1", "to": "notify", "from_port": "false"}
]
}
```
ì ììë ê³ì¢ ìê³ ê° 100ë§ì ì´ìì´ë©´ 주문 ì¤í, 미ë§ì´ë©´ ì림 ë
¸ëë¡ ë¶ê¸°í©ëë¤.
**ì
ë ¥ íë:**
| íë | íì
| ì¤ëª
| ííì |
| ---------- | ------ | ------------------ | ----------------------------- |
| `left` | any | ì¼ìª½ í¼ì°ì°ì | `{{ nodes.account.balance }}` |
| `operator` | string | ë¹êµ ì°ì°ì (기본ê°: `==`) | - |
| `right` | any | ì¤ë¥¸ìª½ í¼ì°ì°ì | `{{ 1000000 }}` |
**ì§ì ì°ì°ì (12ì¢
):**
| ì°ì°ì | ì¤ëª
| ìì |
| -------------- | ------------------- | --------------------------------------- |
| `==` | ê°ì | `"AAPL" == "AAPL"` â true |
| `!=` | ë¤ë¦ | `5 != 3` â true |
| `>` | ì´ê³¼ | `100 > 50` â true |
| `>=` | ì´ì | `100 >= 100` â true |
| `<` | ë¯¸ë§ | `50 < 100` â true |
| `<=` | ì´í | `100 <= 100` â true |
| `in` | í¬í¨ë¨ | `"AAPL" in ["AAPL","TSLA"]` â true |
| `not_in` | 미í¬í¨ | `"MSFT" not_in ["AAPL","TSLA"]` â true |
| `contains` | 문ìì´ í¬í¨ | `"Hello World" contains "World"` â true |
| `not_contains` | 문ìì´ ë¯¸í¬í¨ | `"Hello" not_contains "World"` â true |
| `is_empty` | ë¹ê° (right ë¶íì) | `[] is_empty` â true |
| `is_not_empty` | ë¹ì´ìì§ ìì (right ë¶íì) | `[1,2] is_not_empty` â true |
> **íì
ìë ë³í**: ì«ì ë¹êµ(`>`, `>=`, `<`, `<=`)ìì 문ìì´ `"100"`ê³¼ ì«ì `50`ì ë¹êµíë©´ ìëì¼ë¡ ì«ìë¡ ë³íí©ëë¤. ë³í ë¶ê°ë¥í ê²½ì° `false`를 ë°íí©ëë¤.
**ì¶ë ¥:**
| í¬í¸ | íì
| ì¤ëª
|
| -------- | ------- | --------------------------------- |
| `true` | any | ì¡°ê±´ ì°¸ â upstream ë°ì´í° pass-through |
| `false` | any | ì¡°ê±´ ê±°ì§ â upstream ë°ì´í° pass-through |
| `result` | boolean | ì¡°ê±´ íê° ê²°ê³¼ (`true` / `false`) |
**ë¶ê¸° ì°ê²° (from\_port):**
ì£ì§ì `from_port`를 ì§ì íì¬ ì´ë¤ ë¸ëì¹ì íì ë
¸ëì¸ì§ ëª
ìí©ëë¤:
```json
{"from": "if1", "to": "buy_order", "from_port": "true"}
{"from": "if1", "to": "sell_order", "from_port": "false"}
```
`from_port`ê° ìë ì£ì§ë **íì ì¤í**ë©ëë¤ (í©ë¥ ë
¸ëì ì ì©).
**íì© í¨í´:**
1. **ìê³ íì¸ í 주문**: ìê³ >= ìµìê¸ì¡ â 매ì / ìëë©´ â ë기
2. **ì¢
목 íí°ë§**: ì¢
목ì½ë `in` ê´ì¬ì¢
목 리ì¤í¸ â ë¶ì ì§í
3. **ë¤ë¨ê³ ë¶ê¸°**: IfNode를 ì°ì ë°°ì¹íì¬ `if-elif-else` 구í
{% @mermaid/diagram content="flowchart LR
A\["AccountNode"] --> B\["IfNode
ìê³ >= 100ë§?"]
B -->|true| C\["NewOrderNode
(매ì)"]
B -->|false| D\["FieldMappingNode
(ì림)"]" %}
> **ìºì¤ì¼ì´ë© ì¤íµ**: false ë¸ëì¹ì íì ë
¸ëë¤ì ìëì¼ë¡ ì¤íì´ ì¤íµë©ëë¤. ì¬ë¬ ë
¸ëê° ì°ê²°ëì´ ìì´ë ì¤íµì´ ì íë©ëë¤.
***
## 2. account - ê³ì¢ ì¡°í
ê³ì¢ ìê³ , ë³´ì ì¢
목, 미체결 주문ì ì¡°ííë ë
¸ëë¤ì
ëë¤.
### AccountNode (1íì± ê³ì¢ ì¡°í)
REST APIë¡ íì¬ ìì ì ê³ì¢ ì 보를 **í ë²** ì¡°íí©ëë¤. ì¤ë
ì·ì ì°ë ê²ê³¼ ê°ìµëë¤.
| ìí | ë
¸ë íì
|
| ---- | ---------------------------- |
| í´ì¸ì£¼ì | `OverseasStockAccountNode` |
| í´ì¸ì 물 | `OverseasFuturesAccountNode` |
| êµë´ì£¼ì | `KoreaStockAccountNode` |
```json
{
"id": "account",
"type": "OverseasStockAccountNode"
}
```
**ì¶ë ¥:**
* `held_symbols` - ë³´ì ì¢
목 ì½ë 리ì¤í¸ `["AAPL", "NVDA"]`
* `balance` - ììê¸/매ìê°ë¥ê¸ì¡
* `positions` - ë³´ì ì¢
목 ìì¸ ì ë³´
**positions ì¶ë ¥ ìì:**
```json
[
{
"symbol": "AAPL",
"exchange": "NASDAQ",
"quantity": 10,
"buy_price": 185.50,
"current_price": 192.30,
"pnl_rate": 3.67
},
{
"symbol": "NVDA",
"exchange": "NASDAQ",
"quantity": 5,
"buy_price": 880.00,
"current_price": 920.50,
"pnl_rate": 4.60
}
]
```
> **주ì**: AccountNodeë ì¤í ìì ì ë°ì´í°ë¥¼ 1í ì¡°íí©ëë¤. ì¤ìê°ì¼ë¡ ê³ì ì
ë°ì´í¸ëë ë°ì´í°ê° íìíë©´ RealAccountNodeì ì¬ì©íì¸ì.
> **주ì**: ë³´ì ì¢
ëª©ì´ ìì¼ë©´ `positions`ë ë¹ ë°°ì´ `[]`ì ë°íí©ëë¤. ìê³ ê° 0ì´ë©´ `balance`ë 0ì ë°íí©ëë¤. ìë¬ê° ìëëë¤.
***
### OpenOrdersNode (미체결 주문 ì¡°í)
ìì§ ì²´ê²°ëì§ ìì 주문 목ë¡ì ì¡°íí©ëë¤. ì§ì ê° ì£¼ë¬¸ì ë£ìëë° ìì§ ì²´ê²°ëì§ ìì ê²½ì° ë±ì íì¸í ì ììµëë¤.
| ìí | ë
¸ë íì
|
| ---- | ------------------------------- |
| í´ì¸ì£¼ì | `OverseasStockOpenOrdersNode` |
| í´ì¸ì 물 | `OverseasFuturesOpenOrdersNode` |
| êµë´ì£¼ì | `KoreaStockOpenOrdersNode` |
```json
{
"id": "openOrders",
"type": "OverseasStockOpenOrdersNode"
}
```
**ì¶ë ¥:**
* `open_orders` - 미체결 주문 목ë¡
* `count` - 미체결 주문 ì
**open\_orders ì¶ë ¥ ìì:**
```json
[
{
"order_no": "12345",
"symbol": "AAPL",
"side": "buy",
"order_type": "limit",
"price": 180.00,
"quantity": 10,
"filled_quantity": 0
}
]
```
> **í**: CancelOrderNodeì `ScheduleNode` + `IfNode`를 ì¡°í©íë©´ "30ë¶ ì´ë´ 미체결 ì ìë ì·¨ì" ê°ì ë¡ì§ì ì§ì 구íí ì ììµëë¤.
***
### RealAccountNode (ì¤ìê° ê³ì¢)
WebSocketì¼ë¡ ê³ì¢ ì 보를 **ì¤ìê°** ìì í©ëë¤. ì£¼ë¬¸ì´ ì²´ê²°ëê±°ë ìì¸ê° ë³í ëë§ë¤ ìëì¼ë¡ ì
ë°ì´í¸ë©ëë¤.
| ìí | ë
¸ë íì
|
| ---- | -------------------------------- |
| í´ì¸ì£¼ì | `OverseasStockRealAccountNode` |
| í´ì¸ì 물 | `OverseasFuturesRealAccountNode` |
| êµë´ì£¼ì | `KoreaStockRealAccountNode` |
```json
{
"id": "realAccount",
"type": "OverseasStockRealAccountNode",
"stay_connected": true,
"sync_interval_sec": 60,
"commission_rate": 0.25
}
```
| íë | íì
| ê¸°ë³¸ê° | ì¤ëª
|
| ------------------- | ------- | ------ | ---------------------------------------- |
| `stay_connected` | boolean | `true` | ìí¬íë¡ì° ì¢
ë£ íìë WebSocket ì°ê²° ì ì§ |
| `sync_interval_sec` | number | `60` | REST APIë¡ ì íí ë°ì´í° ë기ííë 주기 (ì´, 10\~3600) |
| `commission_rate` | number | `0.25` | ììë£ì¨ (%), ììµë¥ ê³ì°ì ë°ì |
| `tax_rate` | number | `0.0` | ì¸ì¨ (%), ììµë¥ ê³ì°ì ë°ì |
**ì¶ë ¥:**
* `held_symbols` - ë³´ì ì¢
목 ì½ë
* `balance` - ììê¸
* `open_orders` - 미체결 주문
* `positions` - ë³´ì ì¢
목 (ì¤ìê° ììµë¥ í¬í¨)
**AccountNode vs RealAccountNode ë¹êµ:**
| í목 | AccountNode | RealAccountNode |
| ------ | ---------------- | -------------------- |
| ì°ê²° ë°©ì | REST API (1í ì¡°í) | WebSocket (ì¤ìê° ì¤í¸ë¦¬ë°) |
| ë°ì´í° ê°±ì | í¸ì¶ ìì 1ë² | ì´ë²¤í¸ ë°ì ì ìë ê°±ì |
| ì¬ì© ìì | 매매 ì ìê³ íì¸ | ì¤ìê° ëª¨ëí°ë§, 리ì¤í¬ ê´ë¦¬ |
| 리ìì¤ | ê°ë²¼ì | ì°ê²° ì ì§ íì |
> **주ì**: RealAccountNodeì ë°ì´í°ë ë§¤ì° ë¹ë²íê² ì
ë°ì´í¸ë©ëë¤. íìì 주문 ë
¸ë를 ì°ê²°í ëë ë°ëì **ThrottleNode**를 ì¬ì´ì ë£ì´ì£¼ì¸ì.
> **í - commission\_rate**: í´ì¸ì£¼ì ììë£ë ì¦ê¶ì¬ë§ë¤ ë¤ë¦
ëë¤. LSì¦ê¶ì ê²½ì° ì½ 0.25%ì
ëë¤. ì íí ììµë¥ ê³ì°ì ìí´ ì¤ì ììë£ì¨ì ì
ë ¥íì¸ì.
***
### RealOrderEventNode (ì¤ìê° ì£¼ë¬¸ ì´ë²¤í¸)
ì£¼ë¬¸ì´ ì ì/ì²´ê²°/ì ì /ì·¨ì/ê±°ë¶ë ëë§ë¤ ì¤ìê°ì¼ë¡ ì´ë²¤í¸ë¥¼ ìì í©ëë¤. 주문 ìí를 모ëí°ë§í ë ì¬ì©í©ëë¤.
| ìí | ë
¸ë íì
|
| ---- | ----------------------------------- |
| í´ì¸ì£¼ì | `OverseasStockRealOrderEventNode` |
| í´ì¸ì 물 | `OverseasFuturesRealOrderEventNode` |
| êµë´ì£¼ì | `KoreaStockRealOrderEventNode` |
```json
{
"id": "orderEvents",
"type": "OverseasStockRealOrderEventNode",
"stay_connected": true
}
```
| íë | íì
| ê¸°ë³¸ê° | ì¤ëª
|
| ---------------- | ------- | ------ | ------------------ |
| `stay_connected` | boolean | `true` | WebSocket ì°ê²° ì ì§ ì¬ë¶ |
**ì¶ë ¥ (5ê° í¬í¸):**
ì´ë²¤í¸ ì¢
ë¥ë³ë¡ ë¤ë¥¸ ì¶ë ¥ í¬í¸ë¡ ëê°ëë¤:
| í¬í¸ | ì¤ëª
| ì¸ì ë°ìíëì? |
| ----------- | ------ | ----------------- |
| `accepted` | 주문 ì ìë¨ | ì£¼ë¬¸ì´ ê±°ëìì ì ìëìì ë |
| `filled` | ì²´ê²°ë¨ | ì£¼ë¬¸ì´ ì¤ì ë¡ ì²´ê²°ëìì ë |
| `modified` | ì ì ìë£ | 주문 ê°ê²©/ìëì´ ì ì ëìì ë |
| `cancelled` | ì·¨ì ìë£ | ì£¼ë¬¸ì´ ì·¨ìëìì ë |
| `rejected` | ê±°ë¶ë¨ | ì£¼ë¬¸ì´ ê±°ëììì ê±°ë¶ëìì ë |
**ì¬ì© ìì - ì²´ê²° ì림:**
{% @mermaid/diagram content="flowchart LR
A\[RealOrderEventNode] -->|filled| B\[TableDisplayNode]
A -->|rejected| C\["TableDisplayNode
(ìë¬ ë¡ê·¸)"]" %}
> **í**: `filled` í¬í¸ì ì¡°ê±´ ë¡ì§ì ì°ê²°íë©´ "ì²´ê²°ëë©´ â ìµì /ìì 주문 ìë ë°ì" ê°ì íë¦ì ë§ë¤ ì ììµëë¤.
***
## 3. market - ìì¸/ì¢
목
ìì¸ ì¡°í, ì¢
목 ê²ì, ê´ì¬ì¢
목 ê´ë¦¬ë¥¼ ë´ë¹íë ë
¸ëë¤ì
ëë¤.
### MarketDataNode (íì¬ê° ì¡°í)
REST APIë¡ **ë¹ì¼ íì¬ê°**를 ì¡°íí©ëë¤. ë¨ì¼ ì¢
목 기ë°ì¼ë¡ ëìíë©°, ì¬ë¬ ì¢
목ì ì¡°ííë ¤ë©´ SplitNodeê³¼ ì¡°í©í©ëë¤.
| ìí | ë
¸ë íì
|
| ---- | ------------------------------- |
| í´ì¸ì£¼ì | `OverseasStockMarketDataNode` |
| í´ì¸ì 물 | `OverseasFuturesMarketDataNode` |
| êµë´ì£¼ì | `KoreaStockMarketDataNode` |
```json
{
"id": "market",
"type": "OverseasStockMarketDataNode",
"symbol": "{{ item }}"
}
```
| íë | íì
| íì | ì¤ëª
|
| -------- | ------ | :-: | ----- |
| `symbol` | object | â
| ì¢
목 ì ë³´ |
`symbol` ì§ì ë°©ë²:
* SplitNodeê³¼ í¨ê»: `"{{ item }}"` (ìëì¼ë¡ íì¬ ì¢
목 ì¬ì©)
* ì§ì ì§ì : `{"exchange": "NASDAQ", "symbol": "AAPL"}`
**ì¶ë ¥**: `value` - ìì¸ ë°ì´í°
```json
{
"symbol": "AAPL",
"exchange": "NASDAQ",
"price": 192.30,
"change": 1.50,
"change_pct": 0.79,
"volume": 45123456,
"open": 190.50,
"high": 193.20,
"low": 189.80,
"close": 192.30
}
```
> **MarketDataNode vs HistoricalDataNode**: MarketDataNodeì **ì¤ë íì¬ê° 1ê±´**ë§ ì¡°íí©ëë¤. RSIë MACD ê°ì 기ì ì ì§í를 ê³ì°íë ¤ë©´ 과거 Nì¼ ë°ì´í°ê° íìíë¯ë¡ **HistoricalDataNode**ì ì¬ì©íì¸ì.
***
### FundamentalNode (ì¢
목 íëë©í¸ ì¡°í)
LSì¦ê¶ g3104 APIë¡ **PER, EPS, ìê°ì´ì¡, 52주 ê³ /ì ê°** ë± íëë©í¸ ë°ì´í°ë¥¼ ì¡°íí©ëë¤. **í´ì¸ì£¼ì ì ì©**ì
ëë¤ (í´ì¸ì 물ì íììíì´ë¯ë¡ íëë©í¸ ê°ë
ìì).
| ìí | ë
¸ë íì
|
| ---- | ------------------------------ |
| í´ì¸ì£¼ì | `OverseasStockFundamentalNode` |
| í´ì¸ì 물 | - (ì§ìíì§ ìì) |
```json
{
"id": "fundamental",
"type": "OverseasStockFundamentalNode",
"symbols": [
{"exchange": "NASDAQ", "symbol": "AAPL"},
{"exchange": "NASDAQ", "symbol": "MSFT"}
]
}
```
| íë | íì
| íì | ì¤ëª
|
| --------- | ------ | :-: | ---------------------------- |
| `symbol` | object | - | ë¨ì¼ ì¢
목 (`{exchange, symbol}`) |
| `symbols` | array | - | ë³µì ì¢
목 ë°°ì´ |
`symbol` ëë `symbols` ì¤ íë를 ì§ì í©ëë¤. SplitNodeê³¼ í¨ê» ì¬ì© ì `"symbol": "{{ item }}"`.
**ì¶ë ¥**: `value` / `values` â íëë©í¸ ë°ì´í°
```json
{
"exchange": "NASDAQ", "symbol": "AAPL", "name": "APPLE INC",
"industry": "Technology", "nation": "USA", "exchange_name": "NASDAQ",
"current_price": 264.35, "volume": 45123456, "change_percent": 1.25,
"per": 33.39, "eps": 7.9,
"market_cap": 3869057094000, "shares_outstanding": 14681100000,
"high_52w": 288.62, "low_52w": 169.21, "exchange_rate": 1443.1
}
```
| ì¶ë ¥ íë | ì¤ëª
|
| ---------------------- | ------------- |
| `per` | PER (주ê°ììµë¹ì¨) |
| `eps` | EPS (주ë¹ìì´ìµ) |
| `market_cap` | ìê°ì´ì¡ |
| `shares_outstanding` | ë°í주ìì |
| `high_52w` / `low_52w` | 52주 ìµê³ ê° / ìµì ê° |
| `exchange_rate` | íì¨ |
> **MarketDataNode vs FundamentalNode**: MarketDataNodeì ìì¸(ê°ê²©/ë³ë) ì주ì´ê³ PER/EPSë í¬í¨í©ëë¤. FundamentalNodeì **ìê°ì´ì¡, ì
ì¢
, 52주 ê³ /ì ê°, ë°í주ìì** ë± ì¢
목 기본ì 보를 ì¶ê°ë¡ ì ê³µí©ëë¤.
> **AI ìì´ì í¸ ë구**: `is_tool_enabled = true`ì´ë¯ë¡ AIAgentNodeìì ë구(tool)ë¡ ì§ì í¸ì¶í ì ììµëë¤.
***
### HistoricalDataNode (과거 ì°¨í¸ ì¡°í)
과거 Nì¼ì¹ **OHLCV**(ìê°/ê³ ê°/ì ê°/ì¢
ê°/ê±°ëë) ì°¨í¸ ë°ì´í°ë¥¼ ì¡°íí©ëë¤. RSI, MACD ê°ì 기ì ì ì§í ê³ì°ì íìì
ëë¤.
| ìí | ë
¸ë íì
|
| ---- | ----------------------------------- |
| í´ì¸ì£¼ì | `OverseasStockHistoricalDataNode` |
| í´ì¸ì 물 | `OverseasFuturesHistoricalDataNode` |
```json
{
"id": "history",
"type": "OverseasStockHistoricalDataNode",
"symbol": "{{ item }}",
"interval": "1d",
"start_date": "{{ date.ago(90, format='yyyymmdd') }}",
"end_date": "{{ date.today(format='yyyymmdd') }}"
}
```
| íë | íì
| ê¸°ë³¸ê° | ì¤ëª
|
| ------------ | ------- | ------- | ----------------- |
| `symbol` | object | - | ì¢
목 ì ë³´ |
| `interval` | string | `"1d"` | ë°ì´í° 주기 |
| `start_date` | string | 3ê°ì ì | ì¡°í ììì¼ (YYYYMMDD) |
| `end_date` | string | ì¤ë | ì¡°í ì¢
ë£ì¼ (YYYYMMDD) |
| `adjust` | boolean | `false` | ìì ì£¼ê° ì ì© ì¬ë¶ |
**interval ìµì
:**
| ê° | 주기 | ì©ë |
| ----- | ---- | ------------ |
| `1m` | 1ë¶ë´ | ë¨í/ì¤ìºí |
| `5m` | 5ë¶ë´ | ë¨ê¸° 매매 |
| `15m` | 15ë¶ë´ | ë¨ê¸° 매매 |
| `1h` | 1ìê°ë´ | ì¤ì í¸ë ì´ë© |
| `1d` | ì¼ë´ | **ê°ì¥ ë§ì´ ì¬ì©** |
| `1w` | ì£¼ë´ | ì¤ì¥ê¸° ë¶ì |
| `1M` | ìë´ | ì¥ê¸° ë¶ì |
**ì¶ë ¥**: `value` - OHLCV ë°°ì´
```json
[
{"date": "2025-01-10", "open": 190.0, "high": 193.5, "low": 189.2, "close": 192.3, "volume": 45000000},
{"date": "2025-01-09", "open": 188.5, "high": 191.0, "low": 187.8, "close": 190.0, "volume": 38000000}
]
```
> **주ì - RSI ê¸°ê° ì¤ì **: RSI 14ì¼ì ê³ì°íë ¤ë©´ ìµì 14ì¼ ì´ìì ë°ì´í°ê° íìí©ëë¤. `start_date`를 ëëíê² ì¡ì주ì¸ì. ë³´íµ RSI 14ì¼ ê¸°ì¤ì¼ë¡ ìµì 30ì¼, ê¶ì¥ 90ì¼ ì´ìì
ëë¤.
> **주ì - ë¶ë´ ë°ì´í°**: 1ë¶ë´/5ë¶ë´ì ì¡°í ê°ë¥í 기ê°ì´ ì íì ì
ëë¤ (ìµê·¼ ìì¼). ì¼ë´ì ìë
ì¹ ì¡°í ê°ë¥í©ëë¤.
> **í**: `adjust: true`ë¡ ì¤ì íë©´ ì¡ë©´ë¶í ë±ì´ ë°ìë ìì 주ê°ë¥¼ ì¡°íí©ëë¤. ì¥ê¸° ë°±í
ì¤í¸ì ì ì©í©ëë¤.
***
### RealMarketDataNode (ì¤ìê° ìì¸)
WebSocketì¼ë¡ **ì¤ìê° ìì¸**를 ìì í©ëë¤. ì²´ê²°ì´ ë°ìí ëë§ë¤ ë°ì´í°ê° ì
ë°ì´í¸ë©ëë¤.
| ìí | ë
¸ë íì
|
| ---- | ----------------------------------- |
| í´ì¸ì£¼ì | `OverseasStockRealMarketDataNode` |
| í´ì¸ì 물 | `OverseasFuturesRealMarketDataNode` |
```json
{
"id": "realMarket",
"type": "OverseasStockRealMarketDataNode",
"symbol": "{{ item }}",
"stay_connected": true
}
```
| íë | íì
| ê¸°ë³¸ê° | ì¤ëª
|
| ---------------- | ------- | ------ | ------------------------------- |
| `symbol` | object | - | ì¢
목 (SplitNodeì `{{ item }}` ì¬ì©) |
| `stay_connected` | boolean | `true` | ìí¬íë¡ì° ì¢
ë£ íìë ì°ê²° ì ì§ |
**ì¶ë ¥:**
* `ohlcv_data` - OHLCV ì¤ìê° ë°ì´í°
* `data` - ì ì²´ ìì¸ (íì¬ê°, í¸ê°, ê±°ëë ë±)
> **LSì¦ê¶ ë¯¸êµ ì£¼ì ê±°ë ìê° (íêµìê° ê¸°ì¤)**:
| êµ¬ê° | ê²¨ì¸ (ì머íì 미ì ì©) | ì¬ë¦ (ì머íì ì ì©, 3\~11ì) | ë¹ê³ |
| ----- | ------------------- | -------------------- | -------- |
| 주ê°ê±°ë | 10:00 \~ 17:30 | 09:00 \~ 16:30 | ì§ì ê°ë§ ê°ë¥ |
| í리ë§ì¼ | 18:00 \~ 23:30 | 17:00 \~ 22:30 | ì¥ì ìê°ì¸ |
| ì ê·ì¥ | 23:30 \~ 06:00 (ìµì¼) | 22:30 \~ 05:00 (ìµì¼) | ë©ì¸ ê±°ë ìê° |
| ì íí°ë§ì¼ | 06:00 \~ 09:30 | 05:00 \~ 08:30 | ì¥í ìê°ì¸ |
> ì¤ìê° ìì¸ë ì ê±°ë ìê° ì¤ì ìì ë©ëë¤.
> **주ì**: ì¤ìê° ë
¸ë íìì 주문ì´ë AI ë
¸ë를 ì°ê²°í ëë ë°ëì ThrottleNode를 ê±°ì³ì¼ í©ëë¤.
***
### SymbolQueryNode (ì¢
목 ê²ì)
ì¢
목 ì½ëë ì´ë¦ì¼ë¡ ì¢
목ì ê²ìí©ëë¤. "ì íì ì¢
목ì½ëê° ëì§?" í ë ì¬ì©í©ëë¤.
| ìí | ë
¸ë íì
|
| ---- | -------------------------------- |
| í´ì¸ì£¼ì | `OverseasStockSymbolQueryNode` |
| í´ì¸ì 물 | `OverseasFuturesSymbolQueryNode` |
```json
{
"id": "query",
"type": "OverseasStockSymbolQueryNode",
"keyword": "AAPL"
}
```
**ì¶ë ¥**: `symbols` - ê²ì ê²°ê³¼ ì¢
목 리ì¤í¸
***
### WatchlistNode (ê´ì¬ì¢
목)
ì¬ì©ìê° ì§ì ì§ì íë **ê´ì¬ì¢
목 목ë¡**ì
ëë¤. ìí¬íë¡ì°ìì ì²ë¦¬í ì¢
목ì ì ìíë ê°ì¥ 기본ì ì¸ ë°©ë²ì
ëë¤.
```json
{
"id": "watchlist",
"type": "WatchlistNode",
"symbols": [
{"exchange": "NASDAQ", "symbol": "AAPL"},
{"exchange": "NASDAQ", "symbol": "NVDA"},
{"exchange": "NYSE", "symbol": "TSM"}
]
}
```
| íë | íì
| íì | ì¤ëª
|
| --------- | ----- | :-: | ------------------------------- |
| `symbols` | array | â
| ì¢
목 ëª©ë¡ (`{exchange, symbol}` ë°°ì´) |
**ì¶ë ¥**: `symbols` - ì¢
목 리ì¤í¸
> **주ì - exchange íì**: ì¢
목 ì½ëë§ ë£ì¼ë©´ ì ë©ëë¤. `exchange`(ê±°ëì)ì `symbol`(ì¢
목ì½ë)ì í¨ê» ì§ì í´ì¼ í©ëë¤.
| ê±°ëì | ì½ë | ìì ì¢
목 |
| ------- | -------- | ---------------------- |
| ëì¤ë¥ | `NASDAQ` | AAPL, NVDA, TSLA, MSFT |
| ë´ìì¦ê¶ê±°ëì | `NYSE` | TSM, JPM, V, WMT |
| ìë©ì¤ | `AMEX` | SPY, QQQ, GLD |
***
### MarketUniverseNode (ì§ì 구ì±ì¢
목)
ëì¤ë¥100, S\&P500 ê°ì **ëí ì§ìì 구ì±ì¢
목**ì ìëì¼ë¡ ê°ì ¸ìµëë¤.
> í´ì¸ì£¼ì ì ì©ì
ëë¤. Broker ì°ê²°ì´ íìíì§ ììµëë¤ (ë
립 ì¤í).
```json
{
"id": "universe",
"type": "MarketUniverseNode",
"universe": "NASDAQ100"
}
```
| íë | íì
| ê¸°ë³¸ê° | ì¤ëª
|
| ---------- | ------ | ------------- | ----- |
| `universe` | string | `"NASDAQ100"` | ì§ì ì´ë¦ |
**ì§ì ì¸ë±ì¤:**
| ì¸ë±ì¤ | ì¢
목 ì | ì¤ëª
|
| ----------- | ------ | -------------- |
| `NASDAQ100` | \~101ê° | ëì¤ë¥ ëí주 100ì |
| `SP500` | \~503ê° | S\&P 500 |
| `SP100` | \~100ê° | S\&P 100 (ëí주) |
| `DOW30` | 30ê° | ë¤ì°ì¡´ì¤ ì°ì
íê· |
**ì¶ë ¥**: `symbols` (ì¢
목 리ì¤í¸), `count` (ì¢
목 ì)
> **í**: MarketUniverseNode + ScreenerNodeì ì¡°í©íë©´ "ëì¤ë¥100 ì¤ ìì´ 1000ìµ ì´ì + ê±°ëë 100ë§ì£¼ ì´ì" ê°ì ì¤í¬ë¦¬ëì´ ê°ë¥í©ëë¤.
***
### ScreenerNode (ì¢
목 ì¤í¬ë¦¬ë)
ìê°ì´ì¡, ê±°ëë, ì¹í° ë±ì **ì¡°ê±´ì¼ë¡ ì¢
목ì íí°ë§**í©ëë¤.
> í´ì¸ì£¼ì ì ì©ì
ëë¤. Broker ì°ê²°ì´ íìíì§ ììµëë¤.
```json
{
"id": "screener",
"type": "ScreenerNode",
"market_cap_min": 100000000000,
"volume_min": 1000000,
"sector": "Technology",
"exchange": "NASDAQ",
"max_results": 10
}
```
| íë | íì
| ê¸°ë³¸ê° | ì¤ëª
|
| ---------------- | ------ | ----- | ---------------------------------------- |
| `symbols` | array | - | ì
ë ¥ ì¢
목 리ì¤í¸ (미ì§ì ì ì ì²´ ëì) |
| `market_cap_min` | number | - | ìµì ìê°ì´ì¡ (USD) |
| `market_cap_max` | number | - | ìµë ìê°ì´ì¡ (USD) |
| `volume_min` | number | - | ìµì ì¼ ê±°ëë |
| `sector` | string | - | ì¹í° (Technology, Healthcare, Financial ë±) |
| `exchange` | string | - | ê±°ëì (NASDAQ, NYSE, AMEX) |
| `max_results` | number | `100` | ìµë ê²°ê³¼ ì (1\~500) |
**ì¶ë ¥**: `symbols` (ì¡°ê±´ 충족 ì¢
목), `count` (ê²°ê³¼ ì)
> **í - ìê°ì´ì¡ ë¨ì**: ë¯¸êµ ë¬ë¬ 기ì¤ì
ëë¤. 1000ìµ ë¬ë¬ = `100000000000`, 10ìµ ë¬ë¬ = `1000000000`.
***
### SymbolFilterNode (ì¢
목 ì§í© ì°ì°)
ë ì¢
목 리ì¤í¸ë¥¼ **ë¹êµ/íí°ë§**í©ëë¤. ì§í© ì°ì°(ì°¨ì§í©, êµì§í©, í©ì§í©)ì ìíí©ëë¤.
```json
{
"id": "filter",
"type": "SymbolFilterNode",
"operation": "difference",
"input_a": "{{ nodes.universe.symbols }}",
"input_b": "{{ nodes.account.held_symbols }}"
}
```
| íë | íì
| ê¸°ë³¸ê° | ì¤ëª
|
| ----------- | ---------- | -------------- | ----------- |
| `operation` | string | `"difference"` | ì°ì° ë°©ì |
| `input_a` | expression | - | 첫 ë²ì§¸ ì¢
목 리ì¤í¸ |
| `input_b` | expression | - | ë ë²ì§¸ ì¢
목 리ì¤í¸ |
**operation ìµì
:**
| ì°ì° | ì미 | ì¤ì ìì |
| -------------- | ---------------- | -------------------------- |
| `difference` | Aìë§ ìë ê² (A - B) | ëì¤ë¥100 ì¤ **ìì§ ë³´ì íì§ ìì** ì¢
목 |
| `intersection` | A, B 모ëì ìë ê² | ê´ì¬ì¢
목 ì¤ **íì¬ ë³´ì ì¤ì¸** ì¢
목 |
| `union` | A + B í©ì¹ê¸° | ë 리ì¤í¸ í©ì¹ê¸° (ì¤ë³µ ì ê±°) |
**ì¶ë ¥**: `symbols` (ê²°ê³¼ 리ì¤í¸), `count` (ê°ì)
**ì¬ì© ìì - 미보ì ì¢
ëª©ë§ ë§¤ì:**
{% @mermaid/diagram content="flowchart LR
A\[MarketUniverseNode] --> C\["SymbolFilterNode
(difference)"] --> D\[...매ì ë¡ì§]
B\[AccountNode] --> C" %}
### ExclusionListNode (ê±°ë ì ì¸ ì¢
목)
ê±°ëìì **ì ì¸í ì¢
목**ì ê´ë¦¬í©ëë¤. ìë ì
ë ¥ê³¼ ëì ë°ì¸ë©ì ê²°í©í ì ìê³ , ì
ë ¥ ì¢
목 리ì¤í¸ìì ìë íí°ë§ë ê°ë¥í©ëë¤.
```json
{
"id": "exclusion",
"type": "ExclusionListNode",
"symbols": [
{"exchange": "NASDAQ", "symbol": "NVDA", "reason": "ë³ëì± ê³¼ë¤"},
{"exchange": "NYSE", "symbol": "BA", "reason": "ì¬ê³ 리ì¤í¬"}
],
"default_reason": "리ì¤í¬ ê´ë¦¬",
"input_symbols": "{{ nodes.watchlist.symbols }}"
}
```
| íë | íì
| ê¸°ë³¸ê° | ì¤ëª
|
| ----------------- | ---------- | ---- | --------------------------------------- |
| `symbols` | array | `[]` | ìë ì ì¸ ì¢
목 `[{exchange, symbol, reason}]` |
| `dynamic_symbols` | expression | - | ëì ì ì¸ ì¢
목 ë°ì¸ë© |
| `input_symbols` | expression | - | íí°ë§í ì본 ì¢
목 리ì¤í¸ |
| `default_reason` | string | `""` | ì¬ì 미ì§ì ì 기본 ì¬ì |
**ì¶ë ¥**: `excluded` (ì ì¸ ì¢
목), `filtered` (íí°ë§ ê²°ê³¼), `count` (ì ì¸ ì), `reasons` (ì¢
ëª©ë³ ì¬ì )
**3ê°ì§ íì© í¨í´:**
| í¨í´ | ì¤ëª
| ì¤ì |
| --------------- | -------------------- | ------------------------------------------ |
| ì ì¸ë§ | ì ì¸ ëª©ë¡ ì ì, ë¤ë¥¸ ë
¸ëìì 참조 | `symbols`ë§ ì¤ì |
| ì§ì íí°ë§ | ì
ë ¥ 리ì¤í¸ìì ì ì¸ ì¢
목 ì ê±° | `symbols` + `input_symbols` |
| SymbolFilter ì°ë | ì°¨ì§í© ì°ì°ì¼ë¡ ì ì¸ ì ì© | SymbolFilterNodeì `input_b`ì `excluded` ì°ê²° |
**주문 ìì ì¥ì¹**: ExclusionListNodeê° ìí¬íë¡ì°ì ìì¼ë©´, NewOrderNodeìì ì ì¸ ì¢
목 주문ì **ìë ì°¨ë¨**í©ëë¤ (`ignore_exclusion: true`ë¡ ë¹íì±í ê°ë¥).
### CurrencyRateNode (íì¨ ì¡°í)
**credential ìì´** ì¤ìê° íì¨ì ì¡°íí©ëë¤. ECB ë°ì´í° 기ë°ì frankfurter.app API를 ì¬ì©í©ëë¤.
```json
{
"id": "currency",
"type": "CurrencyRateNode",
"base_currency": "USD",
"target_currencies": ["KRW", "JPY", "EUR"]
}
```
| ì¶ë ¥ | íì
| ì¤ëª
|
| ---------- | ------ | -------------------------------------- |
| `rates` | array | `[{base, target, rate, timestamp}]` ë°°ì´ |
| `krw_rate` | number | USD/KRW íì¨ (KRWê° targetì í¬í¨ë ê²½ì°) |
### FearGreedIndexNode (ê³µí¬/íì ì§ì)
CNNì Fear & Greed Index를 ì¡°íí©ëë¤. **credential ë¶íì**.
```json
{
"id": "fg",
"type": "FearGreedIndexNode"
}
```
| ì¶ë ¥ | íì
| ì¤ëª
|
| ---------------- | ------ | ----------------------------------------------------- |
| `value` | number | 0\~100 (0=ê·¹ë ê³µí¬, 100=ê·¹ë íì) |
| `label` | string | Extreme Fear / Fear / Neutral / Greed / Extreme Greed |
| `previous_close` | number | ì ì¼ ì¢
ê° ì§ì |
> **í**: IfNodeì ì°ê²°íì¬ `value <= 25`ì´ë©´ 매ì, `value >= 75`ì´ë©´ 매ëíë ìë°ì ì ëµì 구ì±í ì ììµëë¤.
> **ê³µíµ**: ì¸ë¶ ìì¥ ë°ì´í° ë
¸ëë retry 기본 íì±í, rate limit, ì¤ìê° ë
¸ë ì§ì ì°ê²° ì°¨ë¨ (ThrottleNode ê²½ì íì) ì¤ì ì ê°ì§ëë¤.
### MarketStatusNode (ì¤ìê° ì¥ì´ìì ë³´)
LSì¦ê¶ JIF TR ê¸°ë° **ì¤ìê° ì¥ì´ìì ë³´** ë
¸ë. 12ê° ìì¥(KOSPI/KOSDAQ/KRX\_FUTURES/NXT/KRX\_NIGHT/US/CN\_AM/CN\_PM/HK\_AM/HK\_PM/JP\_AM/JP\_PM)ì ê°ì¥Â·ì¢
ê°Â·ìí·ë¸ë ì´ì»¤Â·ì¬ì´ëì¹´ ìí를 WebSocket ì¼ë¡ ìì . ë¸ë¡ì»¤ ìí ì¢
ë¥(í´ì¸ì£¼ì/í´ì¸ì 물/êµë´ì£¼ì) 무ê´íê² ì¬ì© ê°ë¥ (BrokerNode ì¸ì
ê³µì , broker ìì´ë ë¶ê°).
**â ï¸ í´ì¸ì 물 미ì§ì**: CME, HKEX Futures, SGX ë±ì JIF ë²ì ë°ì
ëë¤. `markets` Literal ìì ëª
ìì ì¼ë¡ ì ì¸ëì´ ValidationError 를 ë°ììíµëë¤.
```json
{
"id": "market_status",
"type": "MarketStatusNode",
"markets": ["US"],
"stay_connected": true,
"include_extended_hours": false
}
```
| íë | íì
| ê¸°ë³¸ê° | ì¤ëª
|
| ------------------------ | ----------------- | ------- | ------------------------------------------------------------------------------------------------------------------------- |
| `markets` | `List[MarketKey]` | `[]` | 구ë
í ìì¥ íí°. ë¹ ë¦¬ì¤í¸ë 12ê° ì ì²´. `['US']`, `['KOSPI','KOSDAQ']` ë± ë¶ë¶ ì í ê°ë¥. í´ì¸ì 물 í¤(`CME`, `SGX` ë±) 주ì
ì Pydantic ValidationError |
| `stay_connected` | bool | `true` | `true` ë©´ ìí¬íë¡ì° ì¤í ë´ë´ JIF 구ë
ì ì§ (ì¤ìê° ì ì´ ê°ì§), `false` ë©´ 첫 ì¤ë
ì· ìì í í´ì â AI Agent Tool ì¼íì± ì§ìì© |
| `include_extended_hours` | bool | `false` | `true` ë©´ í리ë§ì¼/ìê°ì¸ë¨ì¼ê°/ìíí°ë§ì¼ ë± ìê°ì¸ ì¸ì
ë `*_is_open` í¸ì í¬í¸ìì `True` ë¡ ë°í |
| ì¶ë ¥ í¬í¸ | íì
| ì¤ëª
|
| --------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------- |
| `statuses` | array | ê° ìì¥ ì¤ë
ì· ë°°ì´ `[{market, jangubun, jstatus, jstatus_label, is_open, is_regular_open, is_extended_open, updated_at}, ...]` |
| `event` | object | ìµê·¼ ì ì´ ì´ë²¤í¸ `{market, prev_jstatus, jstatus, transition, label, timestamp}` |
| `us_is_open` | boolean | 미êµì¥(NASDAQ/NYSE/AMEX íµí©) ê°ì¥ ì¬ë¶ |
| `kospi_is_open` | boolean | ì½ì¤í¼ ê°ì¥ ì¬ë¶ |
| `kosdaq_is_open` | boolean | ì½ì¤ë¥ ê°ì¥ ì¬ë¶ |
| `krx_futures_is_open` | boolean | ì½ì¤í¼ íì ê°ì¥ ì¬ë¶ |
| `hk_is_open` | boolean | í콩 ê°ì¥ ì¬ë¶ (ì¤ì /ì¤í ì¤ íëë¼ë ì´ë ¤ìì¼ë©´ True) |
| `cn_is_open` | boolean | ì¤êµ ê°ì¥ ì¬ë¶ (ì¤ì /ì¤í OR) |
| `jp_is_open` | boolean | ì¼ë³¸ ê°ì¥ ì¬ë¶ (ì¤ì /ì¤í OR) |
**주ë§/ì´ë²¤í¸ 미ìì ì ì´ê¸°ê°**: `stay_connected=true` ìì bool í¬í¸ë `False` ë¡ ì´ê¸°í (ë³´ìì ê¸°ë³¸ê° â ì£¼ë§ ì¤ì£¼ë¬¸ ë°©ì§).
**ì¬ì© ìì â ìíê´ë¦¬ 매ë ê²ì´í¸**
```json
{
"nodes": [
{"id": "broker", "type": "OverseasStockBrokerNode", "credential_id": "broker_cred"},
{"id": "market_status", "type": "MarketStatusNode", "markets": ["US"], "stay_connected": true},
{"id": "if_us_open", "type": "IfNode",
"left": "{{ nodes.market_status.us_is_open }}", "operator": "==", "right": true}
],
"edges": [
{"from": "broker", "to": "market_status"},
{"from": "broker", "to": "if_us_open"},
{"from": "if_us_open", "to": "sell_order", "from_port": "true"},
{"from": "if_us_open", "to": "telegram_market_closed", "from_port": "false"}
]
}
```
**AI Agent Tool ë±ë¡**: `is_tool_enabled=True`. LLM ì´ "미êµì¥ ì§ê¸ ì´ë ¤ìì´?" ê°ì ìì°ì´ ì§ììì `markets=['US']` ë¡ í¸ì¶ í `us_is_open` í¬í¸ ë°í. ìì¸í ë´ì©ì `ai_agent_guide.md` 참조.
> **ê±°ëì 매í ì°¸ê³ **: `US` ë JIF ë¨ì¼ ì½ëë¡ NASDAQ, NYSE, AMEX, Dow Jones, S\&P 500 ë± ëª¨ë ë¯¸êµ ê±°ëì를 í¬í¨í©ëë¤. ê±°ëìë³ ì¸ë¶í(NASDAQ ë§ / NYSE ë§)ë JIF ë 벨ìì ì ê³µëì§ ììµëë¤.
***
## 4. condition - ì¡°ê±´ íê°
매ì/매ë ì¡°ê±´ì íë¨íë íµì¬ ë
¸ëë¤ì
ëë¤.
### ConditionNode
**íë¬ê·¸ì¸ 기ë°**ì¼ë¡ 매ì/매ë ì¡°ê±´ì íë¨í©ëë¤. RSI, MACD, 볼린ì ë°´ë ë± ë¤ìí 기ì ì ì§í를 íë¬ê·¸ì¸ì¼ë¡ ì ííì¬ ì¬ì©í©ëë¤.
```json
{
"id": "rsi",
"type": "ConditionNode",
"plugin": "RSI",
"fields": {
"period": 14,
"threshold": 30,
"direction": "below"
}
}
```
| íë | íì
| íì | ì¤ëª
|
| ----------- | ---------- | :-: | ------------------------- |
| `plugin` | string | â
| ì¬ì©í íë¬ê·¸ì¸ ID (RSI, MACD ë±) |
| `fields` | object | â | íë¬ê·¸ì¸ë³ íë¼ë¯¸í° |
| `positions` | expression | ì¡°ê±´ë¶ | í¬ì§ì
ë°ì´í° (ìµì /ìì íë¬ê·¸ì¸ìì íì) |
**íë¬ê·¸ì¸ë³ë¡ íìí ë°ì´í°ê° ë¤ë¦
ëë¤:**
| íë¬ê·¸ì¸ ì í | íì ë°ì´í° | ì°ê²°í ë
¸ë | ìì íë¬ê·¸ì¸ |
| ------- | ------------ | ---------------------- | -------------------------------------- |
| ìê³ì´ ê¸°ë° | 과거 OHLCV ë°ì´í° | HistoricalDataNode | RSI, MACD, BollingerBands, VolumeSpike |
| í¬ì§ì
ê¸°ë° | ë³´ì ì¢
목 ì ë³´ | AccountNodeì positions | ProfitTarget, StopLoss |
**ì¶ë ¥:**
* `result` - ì¡°ê±´ íê° ê²°ê³¼
```json
{
"passed": true,
"passed_symbols": [
{"symbol": "AAPL", "exchange": "NASDAQ", "rsi": 28.5}
],
"analysis": [
{"symbol": "AAPL", "rsi": 28.5, "signal": "oversold"},
{"symbol": "NVDA", "rsi": 55.2, "signal": "neutral"}
]
}
```
* `passed`: ì¡°ê±´ì íµê³¼í ì¢
ëª©ì´ **íëë¼ë** ìì¼ë©´ `true`
* `passed_symbols`: ì¡°ê±´ì íµê³¼í ì¢
목ë§
* `analysis`: 모ë ì¢
목ì ë¶ì ê²°ê³¼
**ì íì ì¸ ì¬ì© í¨í´:**
{% @mermaid/diagram content="flowchart LR
A\[BrokerNode] --> B\[WatchlistNode] --> C\[SplitNode] --> D\[HistoricalDataNode] --> E\["ConditionNode
(RSI)"]
E --> F\["LogicNode
(AND)"]
F --> G\[NewOrderNode]" %}
> **í**: íëì ìí¬íë¡ì°ì ConditionNodeì ì¬ë¬ ê° ë£ê³ , LogicNodeì¼ë¡ ì¡°í©í ì ììµëë¤. ì: "RSI 과매ë **AND** MACD 골ë í¬ë¡ì¤ì¼ ëë§ ë§¤ì".
> ì ì²´ íë¬ê·¸ì¸ 목ë¡ê³¼ íë¼ë¯¸í°: [ì¢
목조건 íë¬ê·¸ì¸](/docs/strategies/stock_condition.md)
***
### LogicNode
ì¬ë¬ ì¡°ê±´ì **ë
¼ë¦¬ì ì¼ë¡ ì¡°í©**í©ëë¤. "RSI **ê·¸ë¦¬ê³ ** MACD", "RSI **ëë** 볼린ì ë°´ë" ê°ì ë³µí© ì¡°ê±´ì ë§ëëë¤.
```json
{
"id": "logic",
"type": "LogicNode",
"operator": "all",
"conditions": [
{
"is_condition_met": "{{ nodes.rsi.result }}",
"passed_symbols": "{{ nodes.rsi.passed_symbols }}"
},
{
"is_condition_met": "{{ nodes.macd.result }}",
"passed_symbols": "{{ nodes.macd.passed_symbols }}"
}
]
}
```
| íë | íì
| íì | ì¤ëª
|
| ------------ | ------ | :-: | ----------------------------------- |
| `operator` | string | â
| ë
¼ë¦¬ ì°ì°ì |
| `threshold` | number | ì¡°ê±´ë¶ | ìê³ê° (`at_least`, `weighted` ë±ìì ì¬ì©) |
| `conditions` | array | â
| ì¡°ê±´ ëª©ë¡ |
**conditions ë°°ì´ í목:**
| íë | ì¤ëª
|
| ------------------ | ---------------------------------- |
| `is_condition_met` | ConditionNodeì result ë°ì¸ë© |
| `passed_symbols` | ConditionNodeì passed\_symbols ë°ì¸ë© |
| `weight` | ê°ì¤ì¹ (`weighted` ì°ì°ìììë§ ì¬ì©, 0\~1) |
**ì°ì°ì ì¤ëª
:**
| ì°ì°ì | ì미 | ì¤ì ìì |
| ---------- | ------------------- | ----------------------------------- |
| `all` | 모ë ì¡°ê±´ ë§ì¡± (AND) | RSI 과매ë **ê·¸ë¦¬ê³ ** MACD 골ë í¬ë¡ì¤ |
| `any` | íë ì´ì ë§ì¡± (OR) | RSI 과매ë **ëë** 볼린ì ë°´ë íë¨ ì´í |
| `not` | 모ë ì¡°ê±´ ë¶ë§ì¡± | RSI 과매ì **ìë** ì¢
목 |
| `xor` | ì íí íëë§ ë§ì¡± | ë ì í¸ ì¤ íëë§ |
| `at_least` | Nê° ì´ì ë§ì¡± | 3ê° ì¡°ê±´ ì¤ **2ê° ì´ì** (threshold: 2) |
| `at_most` | Nê° ì´í ë§ì¡± | ìµë 1ê°ë§ 충족 |
| `exactly` | ì íí Nê° ë§ì¡± | ì íí 2ê° ì¶©ì¡± |
| `weighted` | ê°ì¤ì¹ í©ì´ threshold ì´ì | RSI 40% + MACD 35% + BB 25% = ê°ì¤ ì ì |
**weighted ìì (ì¤ì½ì´ë§):**
```json
{
"id": "logic",
"type": "LogicNode",
"operator": "weighted",
"threshold": 0.6,
"conditions": [
{
"is_condition_met": "{{ nodes.rsi.result }}",
"passed_symbols": "{{ nodes.rsi.passed_symbols }}",
"weight": 0.4
},
{
"is_condition_met": "{{ nodes.macd.result }}",
"passed_symbols": "{{ nodes.macd.passed_symbols }}",
"weight": 0.35
},
{
"is_condition_met": "{{ nodes.bb.result }}",
"passed_symbols": "{{ nodes.bb.result.passed_symbols }}",
"weight": 0.25
}
]
}
```
ì´ ìììì RSI(40%) + MACD(35%) = 75% ⥠60%(threshold)ì´ë©´ 매ì ì í¸ê° ë©ëë¤.
> ìì¸ ê°ì´ë: [ì¡°ê±´ ì¡°í© (LogicNode)](/docs/nodes/logic_guide.md)
***
## 5. order - 주문 ì¤í
ì¤ì 매ì/매ë 주문ì ì¤ííë ë
¸ëë¤ì
ëë¤.
### NewOrderNode (ì ê· ì£¼ë¬¸)
ì ê· ë§¤ì/매ë 주문ì ì¤íí©ëë¤. **íë¬ê·¸ì¸ì ì¬ì©íì§ ìì¼ë©°**, ê³ ì íë(`side`/`order_type`/`order`)를 ì§ì ì¤ì í©ëë¤. `order`ë `PositionSizingNode.order`를 ë°ì¸ë©íë ê²ì´ íì¤ í¨í´ì
ëë¤.
| ìí | ë
¸ë íì
|
| ---- | ----------------------------- |
| í´ì¸ì£¼ì | `OverseasStockNewOrderNode` |
| í´ì¸ì 물 | `OverseasFuturesNewOrderNode` |
| êµë´ì£¼ì | `KoreaStockNewOrderNode` |
```json
{
"id": "order",
"type": "OverseasStockNewOrderNode",
"side": "buy",
"order_type": "market",
"order": "{{ nodes.sizing.order }}"
}
```
| íë | íì
| íì | ì¤ëª
|
| ------------ | -------------------------------------- | :-: | ---------------------------------------------------------- |
| `side` | `"buy"` \| `"sell"` | â
| 매ì/매ë |
| `order_type` | `"market"` \| `"limit"` | â
| ìì¥ê°/ì§ì ê° |
| `price_type` | enum | â | LSì¦ê¶ í¸ê° ì í (`limit`, `market`, `LOO`, `LOC`, `MOO`, `MOC`) |
| `order` | `{symbol, exchange, quantity, price?}` | â
| `PositionSizingNode.order` ë°ì¸ë© ê¶ì¥ (expression-only) |
**ì¶ë ¥**: `result` - 주문 ê²°ê³¼ (ë°°ì´)
```json
[
{
"order_id": "12345",
"exchange": "NASDAQ",
"symbol": "AAPL",
"side": "buy",
"quantity": 10,
"price": 192.30,
"status": "submitted"
}
]
```
> **â ï¸ `plugin: "MarketOrder"` / `"LimitOrder"` ì ì¡´ì¬íì§ ìë ìì ììµëë¤**: 구 ë²ì ê°ì´ëì `plugin` + `fields: {side, amount_type, amount}` í¨í´ì ì¤ì ë¡ êµ¬íëì§ ììì¼ë©° ì¬ì© ì `[log/error] 주문í ì¢
ëª©ì´ ììµëë¤` ê²½ê³ í ì¡°ì©í no-op ë©ëë¤. ë°ëì ìì ê³ ì íë + `PositionSizingNode.order` ë°ì¸ë© í¨í´ì ì¬ì©íì¸ì.
> **ì¤ì - ì¤ìê° ì°ê²° ì°¨ë¨**: ì¤ìê° ë
¸ë(RealMarketDataNode ë±)ìì NewOrderNodeì¼ë¡ **ì§ì ì°ê²°í ì ììµëë¤**. ì´ë¹ ìì ë² ì£¼ë¬¸ì´ ëê°ë ì¬ê³ 를 ë°©ì§í기 ìí´, ë°ëì ThrottleNode를 ì¬ì´ì ë£ì´ì¼ í©ëë¤.
> **주ì - ì¤ì 주문**: í´ì¸ì£¼ì BrokerNodeì 모ìí¬ì를 ì§ìíì§ ìì¼ë¯ë¡, 주문 ë
¸ë를 ì°ê²°íë©´ **ì¤ì ëì¼ë¡ ê±°ë**ë©ëë¤. ì²ììë ìëì¼ë¡ í
ì¤í¸íì¸ì.
> **주ì - ì¬ìë ë¹íì±í**: 주문 ë
¸ëë ë¤í¸ìí¬ ìë¬ë¥¼ ì ì¸íê³ ìë ì¬ìëê° **ë¹íì±í**ëì´ ììµëë¤. ì¤ë³µ 주문ì ë°©ì§í기 ìí ìì ì¥ì¹ì
ëë¤.
> ì ì²´ 주문 íì´íë¼ì¸ ìì: [주문 ë
¸ë ì¬ì©ë²](/docs/strategies/order_condition.md)
***
### ModifyOrderNode (주문 ì ì )
미체결 주문ì ê°ê²©ì´ë ìëì ì ì í©ëë¤. **íë¬ê·¸ì¸ì ì¬ì©íì§ ìì¼ë©°**, `order_id` + `new_price` / `new_quantity` 를 ì§ì ì¤ì í©ëë¤.
| ìí | ë
¸ë íì
|
| ---- | -------------------------------- |
| í´ì¸ì£¼ì | `OverseasStockModifyOrderNode` |
| í´ì¸ì 물 | `OverseasFuturesModifyOrderNode` |
```json
{
"id": "modify",
"type": "OverseasStockModifyOrderNode",
"order_id": "{{ item.order_id }}",
"new_price": "{{ finance.markup(item.price, 1.0) }}"
}
```
| íë | íì
| íì | ì¤ëª
|
| -------------- | ------- | :-: | ----------- |
| `order_id` | string | â
| ì ì ëì 주문 ID |
| `new_price` | number | â | ë³ê²½í ê°ê²© |
| `new_quantity` | integer | â | ë³ê²½í ìë |
> **â ï¸ `TrailingStop` íë¬ê·¸ì¸ì ì¡´ì¬íì§ ììµëë¤**: ê°ê²© ì¶ì ì ì ì ì¤ìê° ìì¸(`OverseasStockRealMarketDataNode` + `ThrottleNode`)ì `OverseasStockOpenOrdersNode`를 ì¡°í©í ìí¬íë¡ì°ìì `new_price`를 ííìì¼ë¡ ì§ì ê³ì°íì¬ êµ¬ííì¸ì.
***
### CancelOrderNode (주문 ì·¨ì)
미체결 주문ì ì·¨ìí©ëë¤. **íë¬ê·¸ì¸ì ì¬ì©íì§ ìì¼ë©°**, `order_id` 를 ì§ì ì¤ì í©ëë¤.
| ìí | ë
¸ë íì
|
| ---- | -------------------------------- |
| í´ì¸ì£¼ì | `OverseasStockCancelOrderNode` |
| í´ì¸ì 물 | `OverseasFuturesCancelOrderNode` |
```json
{
"id": "cancel",
"type": "OverseasStockCancelOrderNode",
"order_id": "{{ item.order_id }}"
}
```
| íë | íì
| íì | ì¤ëª
|
| ---------- | ------ | :-: | --------- |
| `order_id` | string | â
| ì·¨ìí 주문 ID |
> **â ï¸ `TimeStop` íë¬ê·¸ì¸ì ì¡´ì¬íì§ ììµëë¤**: "Në¶ ì´ë´ 미체결 ì ìë ì·¨ì"ë `ScheduleNode`ë¡ ì£¼ê¸°ì ì¼ë¡ `OverseasStockOpenOrdersNode`를 ì¡°ííê³ , 미체결 ìê°ì `IfNode`ë¡ íì í ë¤ `OverseasStockCancelOrderNode`를 í¸ì¶íì¬ ì§ì 구ííì¸ì.
***
### PositionSizingNode (í¬ì§ì
í¬ê¸° ê³ì°)
**주문 ìëì ìëì¼ë¡ ê³ì°**í©ëë¤. "ìê³ ì 10%ë§ í¬ì" ê°ì ìê¸ ê´ë¦¬ ê·ì¹ì ì ì©í©ëë¤.
```json
{
"id": "sizing",
"type": "PositionSizingNode",
"symbol": "{{ item }}",
"balance": "{{ nodes.account.balance }}",
"method": "fixed_percent",
"max_percent": 10
}
```
| íë | íì
| ê¸°ë³¸ê° | ì¤ëª
|
| ---------------- | ---------- | ----------------- | ---------------------------- |
| `symbol` | expression | - | ëì ì¢
목 |
| `balance` | expression | - | ê°ì© ìê³ |
| `market_data` | expression | - | íì¬ê° ì ë³´ (ì í) |
| `method` | string | `"fixed_percent"` | í¬ì§ì
ì¬ì´ì§ ë°©ë² |
| `max_percent` | number | `10` | ìê³ ëë¹ ë¹ì¨ (%) |
| `fixed_amount` | number | - | ê³ ì ê¸ì¡ (fixed\_amount ë°©ë² ì) |
| `fixed_quantity` | number | `1` | ê³ ì ìë (fixed\_quantity ë°©ë² ì) |
**method ìµì
:**
| ë°©ë² | ì¤ëª
| ì¬ì© ìì |
| ---------------- | ------ | ---------------------- |
| `fixed_percent` | ìê³ ì N% | "ìê³ ì 10%ì© í¬ì" (ê°ì¥ ì¼ë°ì ) |
| `fixed_amount` | ê³ ì ê¸ì¡ | "ì¢
ëª©ë¹ $1000ì© í¬ì" |
| `fixed_quantity` | ê³ ì ìë | "ì¢
ëª©ë¹ 10ì£¼ì© ë§¤ì" |
| `kelly` | ì¼ë¦¬ ê³µì | ì¹ë¥ ê¸°ë° ìµì ë¹ì¨ (ê³ ê¸) |
| `atr_based` | ATR ê¸°ë° | ë³ëì± ê¸°ë° ì¬ì´ì§ (ê³ ê¸) |
**ì¶ë ¥**: `order` - 주문 ì ë³´
```json
{
"symbol": "AAPL",
"exchange": "NASDAQ",
"quantity": 5,
"price": 192.30
}
```
**ì íì ì¸ ì¬ì© í¨í´:**
{% @mermaid/diagram content="flowchart LR
A\[AccountNode] -->|balance| C\["PositionSizingNode
(ìê³ ì 10%ë¡ ê³ì°)"]
B\[ConditionNode] -->|ì¢
목| C
C -->|order| D\["NewOrderNode
(ê³ì°ë ìëì¼ë¡ 주문)"]" %}
> **í**: PositionSizingNodeì ì¶ë ¥(`order`)ì NewOrderNodeì `order` íëì ë°ì¸ë©íë©´ ìëì¼ë¡ ê³ì°ë ìëì¼ë¡ 주문ë©ëë¤. ê³¼ëí ì§ì¤ í¬ì를 ë°©ì§íë íµì¬ ë
¸ëì
ëë¤.
***
## 6. risk - 리ì¤í¬ ê´ë¦¬
### PortfolioNode
ë©í° ì ëµ í¬í¸í´ë¦¬ì¤ì **ì본 ë°°ë¶ê³¼ 리밸ë°ì±**ì ê´ë¦¬í©ëë¤. ì¬ë¬ ì ëµì ìê¸ì ì´ë»ê² ëëì§ ê²°ì í©ëë¤.
```json
{
"id": "portfolio",
"type": "PortfolioNode",
"total_capital": 100000,
"allocation_method": "equal",
"rebalance_rule": "drift",
"drift_threshold": 5.0,
"reserve_percent": 10
}
```
| íë | íì
| ê¸°ë³¸ê° | ì¤ëª
|
| ------------------- | ------ | --------- | ----------------- |
| `total_capital` | number | `100000` | ì´ í¬ì ì본 (USD) |
| `allocation_method` | string | `"equal"` | ìê¸ ë°°ë¶ ë°©ë² |
| `rebalance_rule` | string | `"none"` | 리밸ë°ì± ê·ì¹ |
| `drift_threshold` | number | `5.0` | ë°°ë¶ ë¹ì¨ ì´í íì©ì¹ (%) |
| `reserve_percent` | number | `0` | íê¸ ë³´ì ë¹ì¨ (%, ë¹ìê¸) |
**ë°°ë¶ ë°©ë²:**
| ë°©ë² | ì¤ëª
| ìì (3ê° ì ëµ, $100,000) |
| ------------- | ------------------------- | -------------------------- |
| `equal` | ê· ë± ë°°ë¶ | ê°ê° $33,333 |
| `custom` | ì¬ì©ì ì§ì | RSI 50%, MACD 30%, BB 20% |
| `risk_parity` | ë³ëì± ìë¹ë¡ (ë³ëì± ë®ì ì ëµì ë ë§ì´) | ìì í $45,000, 공격í $25,000 ë± |
| `momentum` | ìµê·¼ ììµë¥ ë¹ë¡ (ì ëë ì ëµì ë ë§ì´) | ììµë¥ ëì ì ëµì ìê¸ ì§ì¤ |
**리밸ë°ì± ê·ì¹:**
| ê·ì¹ | ì¤ëª
|
| ---------- | ------------------------------------------- |
| `none` | 리밸ë°ì± ì í¨ (ì´ê¸° ë°°ë¶ ì ì§) |
| `periodic` | 주기ì ì¼ë¡ 리밸ë°ì± (daily/weekly/monthly/quarterly) |
| `drift` | ë°°ë¶ ë¹ì¨ì´ `drift_threshold`% ì´ì ë²ì´ëë©´ 리밸ë°ì± |
| `both` | 주기 + ë리íí¸ ë ë¤ ì ì© |
**ì¶ë ¥**: `combined_equity` (íµí© ìì°ê³¡ì ), `allocation_weights` (ë°°ë¶ ë¹ì¨), `rebalance_signal` (리밸ë°ì± ì í¸), `allocated_capital` (ì ëµë³ ë°°ë¶ ê¸ì¡)
> **í - reserve\_percent**: íì ì¼ì ë¹ì¨ì íê¸ì¼ë¡ ë³´ì íë ê²ì´ ìì í©ëë¤. `reserve_percent: 10`ì´ë©´ ì´ ì본ì 10%를 íê¸ì¼ë¡ ì ì§í©ëë¤.
***
## 7. schedule - ì¤ì¼ì¤/ìê°
### ScheduleNode
í¬ë¡ (cron) ì¤ì¼ì¤ì ë°ë¼ ìí¬íë¡ì°ë¥¼ **ë°ë³µ ì¤í**í©ëë¤. "íì¼ 9ìì ìë ì¤í", "15ë¶ë§ë¤ ì²´í¬" ê°ì ì¤ì¼ì¤ì ì¤ì í©ëë¤.
```json
{
"id": "schedule",
"type": "ScheduleNode",
"cron": "0 */15 9-16 * * mon-fri",
"timezone": "America/New_York"
}
```
| íë | íì
| ê¸°ë³¸ê° | ì¤ëª
|
| ---------- | ------- | -------------------- | ------------------- |
| `cron` | string | `"0 */5 * * * *"` | í¬ë¡ ííì (6-field ê¶ì¥) |
| `timezone` | string | `"America/New_York"` | íìì¡´ |
| `enabled` | boolean | `true` | íì±í ì¬ë¶ |
> **cron í¬ë§·**: ìì ë **6-field (`ì´ ë¶ ì ì¼ ì ìì¼`)** ë¡ íµì¼í©ëë¤. 5-field(`ë¶ ì ì¼ ì ìì¼`)ë ì§ìëì§ë§ í¼ë ë°©ì§ë¥¼ ìí´ ì´ íë를 ëª
ìíì¸ì.
**ì주 ì°ë í¬ë¡ ìì (6-field):**
| ííì | ì¤ëª
|
| ------------------------- | ------------------------- |
| `0 30 9 * * *` | ë§¤ì¼ ì¤ì 9:30 (ë´ì ìê°) |
| `0 */15 9-16 * * mon-fri` | íì¼ 9\~16ì, 15ë¶ë§ë¤ |
| `0 0 9 * * mon` | 매주 ììì¼ ì¤ì 9:00 |
| `0 0 23 * * *` | íêµìê° ê¸°ì¤ ë§¤ì¼ 08:00 (ë´ì 23ì) |
**ì¶ë ¥**: `trigger` - ì¤ì¼ì¤ í¸ë¦¬ê±° ì í¸
> **주ì - timezone**: ë¯¸êµ ì£¼ìì ë´ì ìê°(`America/New_York`)ì¼ë¡ ì¤ì íì¸ì. íêµ ìê°ì¼ë¡ ì¤ì íë©´ ê±°ëìê°ì´ ë§ì§ ììµëë¤.
> **í - LSì¦ê¶ ë¯¸êµ ì£¼ì ê±°ë ìê° (íêµìê° ê¸°ì¤)**:
| êµ¬ê° | ê²¨ì¸ (ì머íì 미ì ì©) | ì¬ë¦ (ì머íì ì ì©, 3\~11ì) | ë¹ê³ |
| ----- | ------------------- | -------------------- | -------- |
| 주ê°ê±°ë | 10:00 \~ 17:30 | 09:00 \~ 16:30 | ì§ì ê°ë§ ê°ë¥ |
| í리ë§ì¼ | 18:00 \~ 23:30 | 17:00 \~ 22:30 | ì¥ì ìê°ì¸ |
| ì ê·ì¥ | 23:30 \~ 06:00 (ìµì¼) | 22:30 \~ 05:00 (ìµì¼) | ë©ì¸ ê±°ë ìê° |
| ì íí°ë§ì¼ | 06:00 \~ 09:30 | 05:00 \~ 08:30 | ì¥í ìê°ì¸ |
> íêµìê° ì¤ì ìë 주ê°ê±°ëë¡ ë¯¸êµ ì£¼ì ë§¤ë§¤ê° ê°ë¥í©ëë¤. ì ê·ì¥ ì¸ ìê°ìë ì§ì ê° ì£¼ë¬¸ë§ ê°ë¥íë¯ë¡ `OverseasStockNewOrderNode`ìì `order_type: "limit"` + `order.price`를 ëª
ìíì¬ ì§ì ê° ì£¼ë¬¸ì ì¬ì©íì¸ì.
> ìì¸ ê°ì´ë: [ì¤ì¼ì¤ ì¤ì ](/docs/nodes/schedule_guide.md)
***
### TradingHoursFilterNode
**ê±°ëìê° íí°**ì
ëë¤. ê±°ëìê°ì´ ìëë©´ ë기íë¤ê°, ê±°ëìê°ì´ ììëë©´ íµê³¼ìíµëë¤.
```json
{
"id": "tradingHours",
"type": "TradingHoursFilterNode",
"start": "09:30",
"end": "16:00",
"timezone": "America/New_York",
"days": ["mon", "tue", "wed", "thu", "fri"]
}
```
| íë | íì
| íì | ì¤ëª
|
| ---------- | ------ | :-: | ----------------------------------------- |
| `start` | string | â
| ìì ìê° (HH:MM) |
| `end` | string | â
| ì¢
ë£ ìê° (HH:MM) |
| `timezone` | string | â
| íìì¡´ |
| `days` | array | â
| íì± ìì¼ (mon, tue, wed, thu, fri, sat, sun) |
**ëì ë°©ì:**
| ìí© | ëì |
| ----------- | --------------------------- |
| ê±°ëìê° ë´ | ì¦ì íµê³¼ |
| ê±°ëìê° ì¸ | ê±°ëìê° ììê¹ì§ **ë기** (blocking) |
| shutdown ìì² | ì¢
ë£ |
**ì¶ë ¥**: `passed` (íµê³¼ ì¬ë¶), `blocked` (ì°¨ë¨ ì¬ë¶)
> **주ì**: ê±°ëìê° ì¸ì ìí¬íë¡ì°ë¥¼ ììíë©´ ì´ ë
¸ëìì **ë©ì¶°ì ë기**í©ëë¤. ScheduleNodeê³¼ ì¡°í©íì¬ ê±°ëìê° ë´ìë§ ì¤íëëë¡ ì¤ì íë ê²ì ê¶ì¥í©ëë¤.
***
## 8. data - ë°ì´í° ì¡°í/ì ì¥
### SQLiteNode
ë¡ì»¬ SQLite ë°ì´í°ë² ì´ì¤ì ë°ì´í°ë¥¼ **ì ì¥íê³ ì¡°í**í©ëë¤. 매매 ì´ë ¥ ì ì¥, ìµê³ ê° ì¶ì ë±ì íì©í©ëë¤.
ë ê°ì§ 모ë를 ì§ìí©ëë¤:
#### 모ë 1: execute\_query (SQL ì§ì ìì±)
SQLì ìê³ ìë¤ë©´ ì§ì 쿼리를 ìì±í ì ììµëë¤.
```json
{
"id": "sqlite",
"type": "SQLiteNode",
"db_name": "trading.db",
"operation": "execute_query",
"query": "SELECT * FROM trade_history WHERE symbol = :symbol",
"parameters": {"symbol": "AAPL"}
}
```
#### 모ë 2: simple (SQL ìì´ CRUD)
SQL ìì´ í
ì´ë¸/ì¡ì
/컬ë¼ì ì ííì¬ ì¬ì©í©ëë¤.
```json
{
"id": "sqlite",
"type": "SQLiteNode",
"db_name": "trading.db",
"operation": "simple",
"table": "peak_tracker",
"action": "upsert",
"columns": ["symbol", "peak_price"],
"values": {"symbol": "AAPL", "peak_price": 195.50},
"on_conflict": "symbol"
}
```
| íë | íì
| íì | ì¤ëª
|
| ------------- | ------ | :-: | ---------------------------------------------------- |
| `db_name` | string | â
| DB íì¼ëª
(ìë ìì±ë¨) |
| `operation` | string | â
| `execute_query` ëë `simple` |
| `query` | string | ì¡°ê±´ë¶ | SQL 쿼리 (execute\_query 모ë) |
| `parameters` | object | â | 쿼리 íë¼ë¯¸í° (`:name` íì) |
| `table` | string | ì¡°ê±´ë¶ | í
ì´ë¸ëª
(simple 모ë) |
| `action` | string | ì¡°ê±´ë¶ | `select` / `insert` / `update` / `delete` / `upsert` |
| `values` | object | ì¡°ê±´ë¶ | ì ì¥í ê° |
| `on_conflict` | string | ì¡°ê±´ë¶ | upsert ì ì¶©ë í¤ (ì: `"symbol"`) |
**ì¶ë ¥**: `rows` (ì¡°í ê²°ê³¼), `affected_count` (ìí¥ í ì)
> **í - upsert**: "ìì¼ë©´ ì
ë°ì´í¸, ìì¼ë©´ ì½ì
"ì
ëë¤. ìµê³ ê° ì¶ì ì²ë¼ í ì¢
ëª©ë¹ íëì ë ì½ë를 ì ì§í ë ì ì©í©ëë¤.
***
### HTTPRequestNode
ì¸ë¶ HTTP API를 í¸ì¶í©ëë¤. ë´ì¤ API, ê²½ì ì§í API ë± ì¸ë¶ ë°ì´í°ë¥¼ ê°ì ¸ì¬ ë ì¬ì©í©ëë¤.
```json
{
"id": "http",
"type": "HTTPRequestNode",
"method": "GET",
"url": "https://api.example.com/news",
"query_params": {"symbol": "AAPL", "limit": "5"},
"timeout_seconds": 30
}
```
| íë | íì
| ê¸°ë³¸ê° | ì¤ëª
|
| ----------------- | ------ | ------- | ---------------------------------------- |
| `method` | string | `"GET"` | HTTP ë©ìë (GET, POST, PUT, PATCH, DELETE) |
| `url` | string | - | ìì² URL |
| `query_params` | object | - | URL 쿼리 íë¼ë¯¸í° |
| `body` | object | - | ìì² ë³¸ë¬¸ (POST/PUT/PATCH) |
| `headers` | object | - | ì¶ê° í¤ë |
| `credential_id` | string | - | API ì¸ì¦ ì ë³´ |
| `timeout_seconds` | number | `30` | íììì (ì´, 1\~300) |
**ì¶ë ¥**: `response` (ìëµ ë°ì´í°), `status_code` (HTTP ìí ì½ë), `success` (ì±ê³µ ì¬ë¶), `error` (ìë¬ ë©ìì§)
> **주ì**: ì¤ìê° ë
¸ëìì HTTPRequestNodeì¼ë¡ ì§ì ì°ê²°íë©´ **ê²½ê³ **ê° íìë©ëë¤. ThrottleNode를 ì¬ì©íì¸ì.
> **í**: ì¸ì¦ì´ íìí APIë `credential_id`ë¡ credentials ì¹ì
ì HTTP ì¸ì¦ ì 보를 참조í©ëë¤. Bearer í í°, í¤ë í¤, Basic ì¸ì¦ ë±ì ì§ìí©ëë¤.
***
### FieldMappingNode
ë°ì´í°ì **íëëª
ì ë³í**í©ëë¤. ì¸ë¶ API ìëµì íëëª
ì´ ProgramGarden íìê³¼ ë¤ë¥¼ ë 매íí´ì¤ëë¤.
```json
{
"id": "mapping",
"type": "FieldMappingNode",
"data": "{{ nodes.http.response }}",
"mappings": [
{"from": "ticker", "to": "symbol"},
{"from": "last_price", "to": "price"},
{"from": "vol", "to": "volume"}
],
"preserve_unmapped": true
}
```
| íë | íì
| ê¸°ë³¸ê° | ì¤ëª
|
| ------------------- | ---------- | ------ | ----------------------------------- |
| `data` | expression | - | ë³íí ë°ì´í° |
| `mappings` | array | - | 매í ê·ì¹ `[{from: "ìëì´ë¦", to: "ìì´ë¦"}]` |
| `preserve_unmapped` | boolean | `true` | 매í ê·ì¹ì ìë íëë ì ì§í ì§ ì¬ë¶ |
**ì¶ë ¥**: `mapped_data` (ë³íë ë°ì´í°)
**ë³í ì **: `{"ticker": "AAPL", "last_price": 192.30, "vol": 45000000}` **ë³í í**: `{"symbol": "AAPL", "price": 192.30, "volume": 45000000}`
> **í**: ConditionNodeì íë¬ê·¸ì¸ì `symbol`, `open`, `high`, `low`, `close`, `volume` ê°ì íì¤ íëëª
ì 기ëí©ëë¤. ì¸ë¶ API ë°ì´í°ë¥¼ ConditionNodeì ë£ê¸° ì ì FieldMappingNodeì¼ë¡ íëëª
ì ë§ì¶°ì£¼ì¸ì.
***
### FileReaderNode (íì¼ ë¦¬ë)
íì¼ì ì½ì´ í
ì¤í¸/ë°ì´í°ë¡ ë³íí©ëë¤. PDF, TXT, CSV, JSON, MD, DOCX, XLSX í¬ë§·ì ì§ìí©ëë¤. AIAgentNodeì ë구ë¡ë ì¬ì© ê°ë¥í©ëë¤.
```json
{
"id": "reader",
"type": "FileReaderNode",
"file_paths": ["/app/data/report.pdf", "/app/data/prices.csv"],
"format": "auto"
}
```
| íë | ì¤ëª
| ê¸°ë³¸ê° |
| ------------------ | -------------------------------------------------------------- | ------- |
| `file_paths` | íì¼ ê²½ë¡ ë°°ì´ | - |
| `file_data_list` | Base64 ì¸ì½ë© íì¼ ë°ì´í° ë°°ì´ | - |
| `format` | í¬ë§· (`auto`, `pdf`, `txt`, `csv`, `json`, `md`, `docx`, `xlsx`) | `auto` |
| `pages` | PDF íì´ì§ ë²ì (ì: `"1-5"`, `"1,3,5"`) | ì ì²´ |
| `encoding` | í
ì¤í¸ ì¸ì½ë© | `utf-8` |
| `extract_tables` | PDF í
ì´ë¸ ì¶ì¶ (pdfplumber) | `false` |
| `sheet_name` | XLSX ìí¸ëª
| 첫 ë²ì§¸ ìí¸ |
| `max_file_size_mb` | íì¼ë¹ ìµë í¬ê¸°(MB) | `10` |
**ì¶ë ¥ í¬í¸**: `texts` (í
ì¤í¸ ë°°ì´), `data_list` (íì±ë ë°ì´í° ë°°ì´), `metadata` (íì¼ ë©íë°ì´í° ë°°ì´)
> **ë³´ì**: íì¼ ê²½ë¡ë `/app/data/` íìë¡ ì íë©ëë¤. ê²½ë¡ íì¶ ê³µê²©ì´ ìë ì°¨ë¨ë©ëë¤.
> **í**: ë³µì íì¼ì í ë²ì ì²ë¦¬íë©´ ì¶ë ¥ì´ ë°°ì´ì´ ëì´ auto-iterateë¡ íì¼ë³ AI ë¶ìì´ ê°ë¥í©ëë¤.
***
## 9. display - ìê°í
ì°¨í¸ì í
ì´ë¸ì ìì±í©ëë¤. ì¤ìê° ë
¸ëì ì°ê²°íë©´ ë°ì´í°ê° **ìëì¼ë¡ ê°±ì **ë©ëë¤.
### TableDisplayNode (í
ì´ë¸)
ë°ì´í°ë¥¼ í
ì´ë¸(í) ííë¡ íìí©ëë¤.
```json
{
"id": "table",
"type": "TableDisplayNode",
"title": "ë³´ì ì¢
목 íí©",
"data": "{{ nodes.account.positions }}",
"columns": ["symbol", "quantity", "buy_price", "current_price", "pnl_rate"],
"limit": 20,
"sort_by": "pnl_rate",
"sort_order": "desc"
}
```
| íë | íì
| ê¸°ë³¸ê° | ì¤ëª
|
| ------------ | ---------- | -------- | --------------------------------- |
| `title` | string | - | í
ì´ë¸ ì 목 |
| `data` | expression | - | íìí ë°ì´í° (ë°°ì´) |
| `columns` | array | ì ì²´ | íìí ì»¬ë¼ ëª©ë¡ (미ì§ì ì 모ë 컬ë¼) |
| `limit` | number | `10` | ìµë í ì (1\~100) |
| `sort_by` | string | - | ì ë ¬ ê¸°ì¤ ì»¬ë¼ |
| `sort_order` | string | `"desc"` | `"asc"` (ì¤ë¦ì°¨ì) ëë `"desc"` (ë´ë¦¼ì°¨ì) |
***
### LineChartNode (ë¼ì¸ ì°¨í¸)
ìê³ì´ ë°ì´í°ë¥¼ ë¼ì¸ ì°¨í¸ë¡ íìí©ëë¤. RSI ì¶ì´, ê°ê²© ë³ë ë±ì ìê°íí ë ì¬ì©í©ëë¤.
```json
{
"id": "chart",
"type": "LineChartNode",
"title": "RSI ì¶ì´",
"data": "{{ nodes.rsi.result.analysis }}",
"x_field": "date",
"y_field": "rsi"
}
```
| íë | íì
| íì | ì¤ëª
|
| --------- | ---------- | :-: | -------------------- |
| `title` | string | â | ì°¨í¸ ì 목 |
| `data` | expression | â
| ì°¨í¸ ë°ì´í° (ë°°ì´) |
| `x_field` | string | â
| Xì¶ íëëª
(ë³´íµ `"date"`) |
| `y_field` | string | â
| Yì¶ íëëª
(ë³´íµ ê° íë) |
> **주ì**: `x_field`ì `y_field`를 ë°ëì ëª
ìí´ì¼ í©ëë¤. ìë ì¶ë¡ ì ì§ìíì§ ììµëë¤.
***
### MultiLineChartNode (ë¤ì¤ ë¼ì¸ ì°¨í¸)
ì¬ë¬ ì리ì¦(ì¢
목)를 **í ì°¨í¸ì** íìí©ëë¤. ì¢
ëª©ë³ ê°ê²© ë¹êµì ì ì©í©ëë¤.
```json
{
"id": "multiChart",
"type": "MultiLineChartNode",
"title": "ì¢
ëª©ë³ ê°ê²© ì¶ì´",
"data": "{{ nodes.history.value }}",
"x_field": "date",
"y_field": "close",
"series_key": "symbol"
}
```
> **주ì**: `HistoricalDataNode`ì ì¶ë ¥ì `.value`(ë¨ì, ë°°ì´) ëë `.value.time_series`(ë¨ì¼ ì¢
목ì ìê³ì´)ì
ëë¤. 구 ë²ì ìì ì°ë `.values`(ë³µì)ë ì¡´ì¬íì§ ììµëë¤.
| íë | íì
| íì | ì¤ëª
|
| ------------ | ------ | :-: | ------------------------------------- |
| `series_key` | string | â
| ìë¦¬ì¦ êµ¬ë¶ í¤ (ì: `"symbol"`ì´ë©´ ì¢
목ë³ë¡ ë¼ì¸ ë¶ë¦¬) |
***
### CandlestickChartNode (ìºë¤ì¤í± ì°¨í¸)
OHLCV ë°ì´í°ë¥¼ **ìºë¤ì¤í±(ë´) ì°¨í¸**ë¡ íìí©ëë¤. 주ì ì°¨í¸ì 기본 ííì
ëë¤.
```json
{
"id": "candle",
"type": "CandlestickChartNode",
"title": "AAPL ì¼ë´",
"data": "{{ nodes.history.value }}",
"date_field": "date",
"open_field": "open",
"high_field": "high",
"low_field": "low",
"close_field": "close",
"volume_field": "volume"
}
```
| íë | íì
| íì | ì¤ëª
|
| -------------- | ------ | :-: | ------ |
| `date_field` | string | â
| ë ì§ íë |
| `open_field` | string | â
| ìê° íë |
| `high_field` | string | â
| ê³ ê° íë |
| `low_field` | string | â
| ì ê° íë |
| `close_field` | string | â
| ì¢
ê° íë |
| `volume_field` | string | â | ê±°ëë íë |
***
### BarChartNode (ë° ì°¨í¸)
ë²ì£¼í ë°ì´í°ë¥¼ ë°(ë§ë) ì°¨í¸ë¡ íìí©ëë¤.
```json
{
"id": "bar",
"type": "BarChartNode",
"title": "ì¢
ëª©ë³ ììµë¥ ",
"data": "{{ nodes.account.positions }}",
"x_field": "symbol",
"y_field": "pnl_rate"
}
```
***
### SummaryDisplayNode (ìì½ ì¹´ë)
íµì¬ ì§í를 **ìì½ ì¹´ë** ííë¡ íìí©ëë¤. ëìë³´ëì KPI ì¹´ëì²ë¼ íëì ë³´ì´ë ìì½ ì ë³´ì
ëë¤.
```json
{
"id": "summary",
"type": "SummaryDisplayNode",
"title": "ê³ì¢ ìì½",
"data": "{{ nodes.account }}"
}
```
***
## 10. analysis - ë°±í
ì¤í¸/ë¶ì
### BacktestEngineNode
과거 ë°ì´í°ë¡ ì ëµì **ê²ì¦**í©ëë¤. ì¤ì ëì í¬ìí기 ì ì "ì´ ì ëµì´ 과거ì ì¼ë§ë ììµì´ ë¬ìê¹?"를 ì뮬ë ì´ì
í©ëë¤.
```json
{
"id": "backtest",
"type": "BacktestEngineNode",
"initial_capital": 10000,
"commission_rate": 0.001,
"position_sizing": "kelly",
"exit_rules": {
"stop_loss_percent": 5,
"take_profit_percent": 15
}
}
```
| íë | íì
| ì¤ëª
|
| ----------------- | ------ | ------------------------------------------- |
| `initial_capital` | number | ì´ê¸° í¬ì ì본 (USD) |
| `commission_rate` | number | ììë£ì¨ (0.001 = 0.1%) |
| `position_sizing` | string | í¬ì§ì
ì¬ì´ì§: `fixed`, `percent`, `kelly`, `atr` |
| `exit_rules` | object | ìë ì²ì° ê·ì¹ |
**exit\_rules ìµì
:**
| íë | ì¤ëª
|
| --------------------- | --------------------------- |
| `stop_loss_percent` | ìì ë¹ì¨ (%) - ì´ ì´ì ìì¤ëë©´ ìë 매ë |
| `take_profit_percent` | ìµì ë¹ì¨ (%) - ì´ ì´ì ì´ìµëë©´ ìë 매ë |
**ì¶ë ¥:**
* `equity_curve` - ìì° ë³ë 곡ì (ë ì§ë³ ìì° ì¶ì´)
* `summary` - ì±ê³¼ ìì½
```json
{
"total_return": 25.3,
"mdd": -8.2,
"win_rate": 62.5,
"sharpe_ratio": 1.85,
"total_trades": 48
}
```
> **í**: `summary`ì `sharpe_ratio`ê° 1.0 ì´ìì´ë©´ ê´ì°®ì ì ëµ, 2.0 ì´ìì´ë©´ ì°ìí ì ëµì¼ë¡ íê°ë©ëë¤. `mdd`(ìµë ëí)ê° -20% ì´íë©´ ìíí ì ììµëë¤.
***
### BenchmarkCompareNode
ì¬ë¬ ë°±í
ì¤í¸ 결과를 **ëëí ë¹êµ**í©ëë¤. "RSI ì ëµ vs Buy & Hold, ì´ë¤ ê² ë ëììê¹?"를 ë¶ìí©ëë¤.
```json
{
"id": "compare",
"type": "BenchmarkCompareNode",
"strategies": [
"{{ nodes.backtestRSI }}",
"{{ nodes.backtestSPY }}"
],
"ranking_metric": "sharpe"
}
```
| íë | íì
| íì | ì¤ëª
|
| ---------------- | ------ | :-: | ---------------------- |
| `strategies` | array | â
| BacktestEngineNode ì¶ë ¥ë¤ |
| `ranking_metric` | string | â | ìì ê¸°ì¤ (기본: `sharpe`) |
**ranking\_metric ìµì
:**
| ì§í | ì¤ëª
| ì¢ì ê° |
| -------- | ---------------- | ----------------- |
| `sharpe` | ìí ëë¹ ììµ (ì¤í ë¹ì¨) | ëììë¡ ì¢ì (>1.0) |
| `return` | ì´ ììµë¥ | ëììë¡ ì¢ì |
| `mdd` | ìµë ëí | ë®ììë¡(0ì ê°ê¹ì¸ìë¡) ì¢ì |
| `calmar` | ììµë¥ / MDD | ëììë¡ ì¢ì |
**ì¶ë ¥:**
* `combined_curve` - íµí© ìì° ê³¡ì (ë¹êµ ì°¨í¸ì©)
* `comparison_metrics` - ì ëµë³ ë¹êµ ì§í
* `ranking` - ìì
**ì¬ì© í¨í´:**
{% @mermaid/diagram content="flowchart LR
A\["BacktestEngineNode
(ë´ RSI ì ëµ)"] --> C\[BenchmarkCompareNode] --> D\[LineChartNode]
B\["BacktestEngineNode
(SPY Buy\&Hold)"] --> C" %}
> **í - Buy & Hold 벤ì¹ë§í¬**: BacktestEngineNodeì ì¡°ê±´ ì í¸ ìì´ ë°ì´í°ë§ ë£ì¼ë©´ **Buy & Hold** (ì¬ì ë³´ì ) ì ëµì¼ë¡ ìë ì ì©ë©ëë¤. ë´ ì ëµì´ ë¨ì ë³´ì ë³´ë¤ ëìì§ ë¹êµíì¸ì.
***
## 11. ai - AI ìì´ì í¸
### LLMModelNode
LLM(ëê·ëª¨ ì¸ì´ 모ë¸) APIì ì°ê²°í©ëë¤. BrokerNodeì´ ì¦ê¶ì¬ì ì°ê²°íë¯, LLMModelNodeì **AI ìë¹ì¤ì ì°ê²°**í©ëë¤.
```json
{
"id": "llm",
"type": "LLMModelNode",
"credential_id": "my-openai-cred",
"model": "gpt-4o",
"temperature": 0.3,
"max_tokens": 2000
}
```
| íë | íì
| ê¸°ë³¸ê° | ì¤ëª
|
| --------------- | ------- | ---------- | ---------------------------- |
| `credential_id` | string | - | LLM API ì¸ì¦ ID |
| `model` | string | `"gpt-4o"` | ì¬ì©í 모ë¸ëª
|
| `temperature` | number | `0.7` | ìëµì ì°½ìì± (0.0=ì í, 2.0=ì°½ìì ) |
| `max_tokens` | number | `1000` | ìµë ìëµ ê¸¸ì´ (í í° ì, 100\~128000) |
| `streaming` | boolean | `false` | ìëµì ì¤ìê°ì¼ë¡ ë°ìì§ ì¬ë¶ |
**ì§ì LLM ì ê³µì:**
| ì ê³µì | credential íì
| ëí ëª¨ë¸ |
| ------------ | ------------------ | --------------------------- |
| OpenAI | `llm_openai` | gpt-4o, gpt-4o-mini |
| Anthropic | `llm_anthropic` | claude-sonnet-4-5-20250929 |
| Google | `llm_google` | gemini-2.0-flash |
| Azure OpenAI | `llm_azure_openai` | (ë°°í¬ ì´ë¦ ì¬ì©) |
| Ollama | `llm_ollama` | llama3, mistral (ë¡ì»¬ ì¤í, 무ë£) |
**ì¶ë ¥**: `connection` - LLM ì°ê²° (`ai_model` ì£ì§ë¡ AIAgentNodeì ì ë¬)
> **í - temperature**: í¬ì ë¶ìì²ë¼ ì íì±ì´ ì¤ìí ìì
ì `temperature: 0.1~0.3`ì ê¶ì¥í©ëë¤. ì°½ìì ì¸ ì ëµ ìì´ëì´ê° íìíë©´ `0.7~1.0`ì¼ë¡ ì¬ë¦¬ì¸ì.
> **í - Ollama**: 무ë£ë¡ AI를 ì¬ì©íê³ ì¶ë¤ë©´ Ollama를 ë¡ì»¬ì ì¤ì¹íì¬ ì¬ì©í ì ììµëë¤. ë¨, ì±ë¥ì OpenAI/Anthropicë³´ë¤ ë®ì ì ììµëë¤.
***
### AIAgentNode
AI ìì´ì í¸ê° ìí¬íë¡ì°ì ë¤ë¥¸ ë
¸ë를 \*\*ë구(Tool)\*\*ë¡ íì©íì¬ ìì¥ì ë¶ìíê³ ìì¬ê²°ì í©ëë¤.
```json
{
"id": "agent",
"type": "AIAgentNode",
"preset": "technical_analyst",
"user_prompt": "AAPL, NVDAì ìµê·¼ ì°¨í¸ë¥¼ ë¶ìíê³ ë§¤ì ì ì ì±ì íë¨í´ì£¼ì¸ì.",
"output_format": "json",
"max_tool_calls": 10,
"cooldown_sec": 60
}
```
| íë | íì
| ê¸°ë³¸ê° | ì¤ëª
|
| ----------------- | ------ | ---------- | ----------------------------------- |
| `preset` | string | `"custom"` | ìì´ì í¸ ìí í리ì
|
| `system_prompt` | string | - | AIìê² ì£¼ë ìí ì§ì (custom 모ëìì íì) |
| `user_prompt` | string | - | AIìê² ì§ë¬¸/ì§ì (ííì ì¬ì© ê°ë¥) |
| `output_format` | string | `"text"` | ìëµ íì: `text`, `json`, `structured` |
| `output_schema` | object | - | `structured` 모ëìì ìëµ êµ¬ì¡° ì ì |
| `max_tool_calls` | number | `10` | AIê° ë구를 ìµë ëª ë² í¸ì¶í ì ìëì§ (1\~50) |
| `timeout_seconds` | number | `60` | ìµë ì¤í ìê° (ì´) |
| `cooldown_sec` | number | `60` | ì°ì ì¤í ê° ìµì ë기 ìê° (ì´, 1\~3600) |
**í리ì
ìí :**
| í리ì
| ìí | ì í©í ìí© |
| ------------------- | ------- | ------------------------- |
| `technical_analyst` | 기ì ì ë¶ìê° | RSI, MACD ë± ì°¨í¸ ë¶ì |
| `risk_manager` | 리ì¤í¬ ê´ë¦¬ì | í¬ì§ì
ìíë íê° |
| `news_analyst` | ë´ì¤ ë¶ìê° | ë´ì¤/ì´ë²¤í¸ì ì£¼ê° ìí¥ ë¶ì |
| `strategist` | ì¢
í© ì ëµê° | ì ì²´ í¬í¸í´ë¦¬ì¤ ì ëµ ì립 |
| `custom` | ì¬ì©ì ì ì | `system_prompt`ë¡ ì§ì ìí ì§ì |
**ì°ê²° ë°©ë² (3ê°ì§ ì£ì§ íì
):**
```json
{
"edges": [
{"from": "llm", "to": "agent", "type": "ai_model"},
{"from": "history", "to": "agent", "type": "tool"},
{"from": "market", "to": "agent", "type": "tool"},
{"from": "broker", "to": "agent"}
]
}
```
| ì£ì§ íì
| ì©ë | íì |
| ----------- | ---------------------------------- | :---------: |
| `ai_model` | LLMModelNode â AIAgentNode (AI ì°ê²°) | â
(1ê°) |
| `tool` | 기존 ë
¸ë â AIAgentNode (ëêµ¬ë¡ ë±ë¡) | â (ì¬ë¬ ê° ê°ë¥) |
| `main` (기본) | ì¤í ìì | - |
**ì¶ë ¥**: `response` - AI ìëµ
> **ì¤ì**: `tool` ì£ì§ë¡ ì°ê²°ë ë
¸ëë AIê° **íìí ëë§ í¸ì¶**í©ëë¤. íì ì¤íëë ê²ì´ ìëë¼, AIê° "ì´ ë°ì´í°ê° íìíë¤"ê³ íë¨íì ëë§ í¸ì¶ë©ëë¤.
> **ì¤ì - ì¤ìê° ì°ê²° ì°¨ë¨**: ì¤ìê° ë
¸ëìì AIAgentNodeì¼ë¡ ì§ì ì°ê²°í ì ììµëë¤. ThrottleNode를 ì¬ì´ì ë£ì´ì¼ í©ëë¤.
> **주ì - Stateless**: AI ìì´ì í¸ë 매 ì¤íë§ë¤ **ì´ì ëí를 기ìµíì§ ììµëë¤**. íìí ì ë³´ë `user_prompt`ì ííìì¼ë¡ ì ë¬íì¸ì.
> **주ì - API ë¹ì©**: LLM APIë ì¬ì©ëì ë°ë¼ ë¹ì©ì´ ë°ìí©ëë¤. `cooldown_sec`ì ì ì í ì¤ì íì¬ ê³¼ëí í¸ì¶ì ë°©ì§íì¸ì.
> ìì¸ ê°ì´ë: [AI ìì´ì í¸ ê°ì´ë](/docs/nodes/ai_agent_guide.md)
***
## ë¶ë¡: ë
¸ë ì¹´í
ê³ ë¦¬ ìì½
| ì¹´í
ê³ ë¦¬ | ë
¸ë ì | ì©ë | 주ì ë
¸ë |
| ----------- | ---- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `infra` | 8 | ìì/ì°ê²°/íë¦/ë¶ê¸° | StartNode, BrokerNode, ThrottleNode, SplitNode, AggregateNode, IfNode |
| `account` | 12 | ê³ì¢ ì¡°í | AccountNode, OpenOrdersNode, RealAccountNode, RealOrderEventNode (í´ì¸ì£¼ì/ì 물 + êµë´ì£¼ì) |
| `market` | 23 | ìì¸/ì¢
목/íëë©í¸/íì¨/ì¬ë¦¬/ì ì¸ì¢
목/ì¥ì´ìì ë³´ | MarketDataNode, FundamentalNode, HistoricalDataNode, RealMarketDataNode, WatchlistNode, ScreenerNode, SymbolFilterNode, ExclusionListNode, CurrencyRateNode, FearGreedIndexNode, FundamentalDataNode, MarketStatusNode, KoreaStock\* |
| `condition` | 2 | ì¡°ê±´ íê° | ConditionNode, LogicNode |
| `order` | 10 | 주문 ì¤í | NewOrderNode, ModifyOrderNode, CancelOrderNode, PositionSizingNode (í´ì¸ì£¼ì/ì 물 + êµë´ì£¼ì) |
| `risk` | 1 | 리ì¤í¬ ê´ë¦¬ | PortfolioNode |
| `schedule` | 2 | ì¤ì¼ì¤/ìê° | ScheduleNode, TradingHoursFilterNode |
| `data` | 4 | ë°ì´í° ì¡°í/ì ì¥ | SQLiteNode, HTTPRequestNode, FieldMappingNode, FileReaderNode |
| `display` | 6 | ìê°í | TableDisplayNode, LineChartNode, MultiLineChartNode, CandlestickChartNode, BarChartNode, SummaryDisplayNode |
| `analysis` | 2 | ë°±í
ì¤í¸ | BacktestEngineNode, BenchmarkCompareNode |
| `ai` | 2 | AI ìì´ì í¸ | LLMModelNode, AIAgentNode |
| `messaging` | 1 | ì림/ë©ìì§ | TelegramNode |
***
## ë¤ì ë¨ê³
* [ìí¬íë¡ì° 구조 ì´í´](/docs/workflow/structure.md) - ë
¸ë, ì£ì§, ì¸ì¦ì ê°ë
ë¶í°
* [ìë ë°ë³µ ì²ë¦¬](/docs/workflow/auto_iterate_guide.md) - ì¬ë¬ ì¢
목ì ìëì¼ë¡ ì²ë¦¬íë ë°©ë²
* [ííì 문ë²](/docs/workflow/expression_guide.md) - `{{ }}` ííì ìì±ë²
* [ì¡°ê±´ ì¡°í©](/docs/nodes/logic_guide.md) - ì¬ë¬ ì¡°ê±´ì ë
¼ë¦¬ ì°ì°ì¼ë¡ ì¡°í©
* [ì¢
목조건 íë¬ê·¸ì¸](/docs/strategies/stock_condition.md) - RSI, MACD ë± 77ê° ì ëµ íë¬ê·¸ì¸
* [AI ìì´ì í¸](/docs/nodes/ai_agent_guide.md) - LLMì¼ë¡ ìì¥ ë¶ì