โ ๏ธ ์ฃผ์: ์คํ์์ค ์ฌ์ฉ ์ ๋ฐ์ํ๋ ๋ฌธ์ ์ ๋ํ ์ฑ ์์ ์ฌ์ฉ์์๊ฒ ์์ผ๋ฉฐ, ๋ผ์ด์ ์ค๋ฅผ ๋ฐ๋์ ํ์ธํด ์ฃผ์ธ์. ๋ผ์ด์ ์ค ๋ณด๊ธฐ
โ ๏ธ ๋ชจ์ํฌ์ ์๋ด: ํด์ธ์ ๋ฌผ์ํ์ฝฉ๊ฑฐ๋์ (HKEX)์ ๋ชจ์ํฌ์๋ง ์ง์๋๋ฉฐ,CME,EUREX๋ฑ ๋ค๋ฅธ ๊ฑฐ๋์์ ํด์ธ์ฃผ์์ ๋ชจ์ํฌ์๊ฐ ์ง์๋์ง ์์ต๋๋ค (์ค์ ํฌ์๋ง ๊ฐ๋ฅ). ๋ชจ์ํฌ์ ์ ์ค์ ์ฒด๊ฒฐ ๊ฐ๊ฒฉ๊ณผ ์ฐจ์ด๊ฐ ๋ฐ์ํ๋ ์ ์ํ์๊ธฐ ๋ฐ๋๋๋ค. ๋น ๋ฅธ ์คํ ๊ฐ์ด๋ ๋ณด๊ธฐ
๐ข ํํฉ: ๊ตญ๋ด์ฃผ์ Finance API(88๊ฐ TR) + ์ํฌํ๋ก์ฐ ๋ ธ๋ 13๊ฐ๊ฐ ์ถ๊ฐ๋์์ต๋๋ค. ์ฝ์ธ์ ์ ์์ค์ ๋๋ค.
ProgramGarden์ ์คํ์์ค ๊ธฐ๋ฐ AI ํํธ ํ๋ซํผ์ ๋๋ค. ์ฝ๋ฉ ์์ด ๋ ธ๋๋ฅผ ์กฐํฉํ์ฌ ์๋๋งค๋งค ์ ๋ต์ ๊ตฌ์ฑํ๊ณ ์คํํ ์ ์์ต๋๋ค.
ํ๋ก๊ทธ๋จ ๋์ฐ๊ณผ LS์ฆ๊ถ ํ์ ์ผ๋ก ๊ฐ๋ฐ๋์์ผ๋ฉฐ, ๊ฐ์ธ ํฌ์์๋ถํฐ ์๋๋งค๋งค ์๋น์ค๋ฅผ ์ํ๋ ๊ธฐ์ ๊น์ง ํ์ฉํ ์ ์์ต๋๋ค.
์์ธํ ์ฌ์ฉ๋ฒ์ ๊ฐ์ด๋ ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํ์ธ์.
์คํ์์ค ๊ธฐ๋ฐ์ผ๋ก ๊ตฌ์ถ๋ ์น์ฌ์ดํธ์ ์ฑ์์ ์ด์ฉํ์ธ์.
- https://programgarden.com (์คํ ์์ )
- ์นด์นด์คํก ๋จํก๋ฐฉ: https://open.kakao.com/o/gKVObqUh
- ํ๋ก๊ทธ๋จ ๋์ฐ ์ ํ๋ธ: https://youtube.com/@programgarden
- ๋ค์ด๋ฒ ์นดํ ์ปค๋ฎค๋ํฐ: https://cafe.naver.com/programgarden
- ๋น์ฆ๋์ค ๋ฌธ์: [email protected]
- ๋ ธ๋ ๊ธฐ๋ฐ ์ํฌํ๋ก์ฐ โ 73๊ฐ ๋ ธ๋๋ฅผ ์กฐํฉํ์ฌ ์ฝ๋ฉ ์์ด ์ ๋ต ๊ตฌ์ฑ
- ํด์ธ์ฃผ์ ยท ํด์ธ์ ๋ฌผ ยท ๊ตญ๋ด์ฃผ์ โ LS์ฆ๊ถ OpenAPI ๊ธฐ๋ฐ ์ค์๊ฐ ์์ธ ์กฐํ ๋ฐ ์๋ ์ฃผ๋ฌธ
- AI Agent โ LLM ๊ธฐ๋ฐ ๋ถ์ ๋ฐ ์์ฌ๊ฒฐ์ ์ ์ํฌํ๋ก์ฐ์ ํตํฉ
- ์ ๋ต ํ๋ฌ๊ทธ์ธ โ RSI, MACD ๋ฑ ์ปค๋ฎค๋ํฐ ๊ธฐ์ฌ ์ ๋ต์ ์กฐํฉํ์ฌ ํ์ฉ
- ์ํ ๊ด๋ฆฌ โ ํฌํธํด๋ฆฌ์ค ์ถ์ , HWM/Drawdown, ์ํ ์ด๋ฒคํธ ๊ฐ์ฌ ๊ธฐ๋ก
- ๋์ ๋ ธ๋ ์ฃผ์ โ ์ธ๋ถ ๊ฐ๋ฐ์๊ฐ ๋ฐํ์์ ์ปค์คํ ๋ ธ๋๋ฅผ ์ถ๊ฐ ๊ฐ๋ฅ
src/
โโโ programgarden/ # ์ํฌํ๋ก์ฐ ์คํ ์์ง (๋ฉ์ธ ํจํค์ง)
โ โโโ examples/ # ์ํฌํ๋ก์ฐ ์์ (workflows JSON, dynamic_plugins, programmer_example)
โโโ core/ # ๋
ธ๋ ํ์
, ๋ฒ ์ด์ค ํด๋์ค, ๋ ์ง์คํธ๋ฆฌ, i18n
โโโ finance/ # LS์ฆ๊ถ OpenAPI ๋ํผ (ํด์ธ์ฃผ์, ํด์ธ์ ๋ฌผ, ๊ตญ๋ด์ฃผ์)
โ โโโ example/ # LS์ฆ๊ถ ๋ฐ์ดํฐ API ํธ์ถ ์์ (TR ๋จ์)
โโโ community/ # ์ ๋ต ํ๋ฌ๊ทธ์ธ (RSI, MACD ๋ฑ)
- ์ํฌํ๋ก์ฐ(์๋๋งค๋งค):
src/programgarden/examples/workflows/โ 77๊ฐ ์คํ ๊ฐ๋ฅํ ์ํฌํ๋ก์ฐ JSON + ๋๋ฐ.md๋ฌธ์dynamic_plugins/,dynamic_nodes/โ ๋ฐํ์ ๋์ ์ฃผ์ ์์programmer_example/โ AI Agent ยท quant ํตํฉ ์คํฌ๋ฆฝํธ
- LS์ฆ๊ถ ๋ฐ์ดํฐ API:
src/finance/example/- ํด์ธ์ฃผ์ ยท ํด์ธ์ ๋ฌผ ยท ๊ตญ๋ด์ฃผ์ TR ํธ์ถ ์ํ
์ํฌํ๋ก์ฐ ์์ง ์ ์ฒด (๋ ธ๋ + ์ ๋ต ํ๋ฌ๊ทธ์ธ + finance + core ํฌํจ):
pip install programgarden
# ๋๋ Poetry
poetry add programgardenLS์ฆ๊ถ OpenAPI ๋ง ๋จ๋ ์ฌ์ฉ (์ํฌํ๋ก์ฐ ์์ง ์์ด TR ํธ์ถ ์คํฌ๋ฆฝํธ๋ง ํ์ํ ๋):
pip install programgarden-finance
# ๋๋ Poetry
poetry add programgarden-financeProgramGarden ์ ๋ ์ข ๋ฅ์ ์ฌ์ฉ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํฉ๋๋ค. ์์ ์ด ํ๋ ค๋ ์์ ์ ํด๋นํ๋ ์น์ ์ ํผ์น ๋ค, ์์ชฝ ์ฝ๋ ๋ธ๋ก(์ฐ์๋จ ๋ณต์ฌ ๋ฒํผ)์ ํต์งธ๋ก ๋ณต์ฌํด AI ์์ด์ ํธ์ ์์คํ ํ๋กฌํํธ ๋๋ ์ฒซ ๋ฉ์์ง์ ๋ถ์ฌ ๋ฃ์ผ์ธ์. ๋๋ฉ์ธ ํนํ ์ฝ๋๋ฒ ์ด์ค(์ํฌํ๋ก์ฐ DSL + LS์ฆ๊ถ OpenAPI)๋ผ ์ฝ๋ ๋ฆฌ๋ฉ๋ง์ผ๋ก๋ ์ ํํ ์ถ๋ก ์ด ์ด๋ ต๊ธฐ ๋๋ฌธ์, ์๋จ์ ์ปจํ ์คํธ๋ฅผ ์ฃผ๋ ๊ฒ์ด ์ถ๋ ฅ ํ์ง์ ํฌ๊ฒ ์ข์ฐํฉ๋๋ค.
์ํฌํ๋ก์ฐ ์ฌ์ฉ์์ฉ (programgarden โ ๋
ธ๋ ๊ธฐ๋ฐ ์๋ํ)
WorkflowExecutor ๋ก ์คํํ ์ํฌํ๋ก์ฐ JSON ์ ์์ฑํ๊ฑฐ๋ ๋๋ฒ๊น
ํ ๋ ์ฌ์ฉํฉ๋๋ค. ์๋ ๋ธ๋ก์ ํต์งธ๋ก ๋ณต์ฌํด ์์ด์ ํธ์๊ฒ ๋ถ์ฌ ๋ฃ์ผ์ธ์.
# ProgramGarden โ Workflow User Context
You are helping a user of the ProgramGarden automated-trading library
(https://github.com/programgarden/programgarden). They are building or debugging
workflow JSON that runs through `WorkflowExecutor`. Follow this context strictly.
## What this library is
- Node-based automation DSL. A workflow is a JSON document with `nodes`,
`edges`, `credentials`, and `notes`.
- 73 nodes across 12 categories: `infra` / `account` / `market` / `condition` /
`order` / `risk` / `schedule` / `data` / `display` / `analysis` / `ai` /
`messaging`. Full schema lives in `CLAUDE.md` and
`src/core/programgarden_core/nodes/`.
- 77 community plugins, referenced via the `plugin` field in `ConditionNode`,
`NewOrderNode`, etc. See `src/community/programgarden_community/plugins/`.
- Expression binding: `{{ nodes.<id>.<port> }}` flows data between nodes.
Auto-iterate (`item` / `index` / `total`) when an upstream node emits an
array. Function namespaces: `date.*`, `finance.*`, `stats.*`, `format.*`,
`lst.*`.
- Edge types: `main` (default DAG execution), `ai_model` (connects
`LLMModelNode` โ `AIAgentNode`), `tool` (registers a node as an AI Agent
tool). `IfNode` branches use `from_port: "true"` / `"false"` (or dot
notation `"from": "if1.true"`).
- i18n keys live in `src/core/programgarden_core/i18n/locales/{ko,en}.json`
under the patterns `nodes.{Type}.name|description`,
`fields.{Type}.{field}`, `outputs.{Type}.{port}`.
- Two execution entry points:
(1) `WorkflowExecutor` โ run an entire JSON workflow.
(2) `NodeRunner` โ run a single node standalone.
## Prompt templates
### Build a new workflow
```
First read `CLAUDE.md` to learn the node / edge / expression rules, then study
`src/programgarden/examples/workflows/01-account-stock-balance.json` plus one
or two strategy workflows in the same directory.
Then build the following workflow JSON:
- Goal: buy at market for 5 NASDAQ tickers whose RSI is <= 30
- Constraint: must pass `WorkflowExecutor.validate()`
```
### Debug a failing workflow
```
Running this workflow JSON raises `Node X failed: ...`.
Run it in dry-run mode by passing
`context_params={"dry_run": True, "max_cycles": 1}` to
`WorkflowExecutor.execute()`. Order, messaging, and real-time nodes will
return mock results so you can locate where the actual error happens.
Wire up an `ExecutionListener`
(see `src/core/programgarden_core/bases/listener.py`) to print node and edge
state transitions while it runs.
```
### Contribute a new plugin
```
Add a new strategy plugin `IchimokuCloud` to ProgramGarden. The plugin layout
is a single `__init__.py` inside
`src/community/programgarden_community/plugins/<plugin_name>/` plus an
optional `README.md`. See `plugins/rsi/__init__.py` for the canonical
example. Plugins are registered through `plugins/__init__.py`. Write all i18n
keys in English only.
```
## Gotchas โ call these out up front, they trip agents constantly
1. Symbols are arrays, never dict keys:
`[{"symbol": "AAPL", "exchange": "NASDAQ"}]`
2. Broker connection is auto-injected by Executor via DAG traversal โ never
bind `connection` manually.
3. Method chaining inside `{{ }}` is supported:
`{{ nodes.account.filter('pnl > 0').count() }}`
4. Retry is disabled by default for order nodes (`*NewOrderNode`,
`*ModifyOrderNode`, `*CancelOrderNode`) to prevent duplicate submissions.
Enabling `resilience.retry.enabled = True` needs explicit justification.
5. Auto-iterate: when the upstream node emits an array, the downstream node
runs once per item โ no explicit loop needed.
6. There is **no** `WorkflowExecutor.dry_run()` method. Dry-run is enabled
via `execute(..., context_params={"dry_run": True})`.
## Reference files to read before answering
- `src/programgarden/programgarden/executor.py` โ `WorkflowExecutor`,
`execute()`, `validate()`, dry-run behavior
- `src/core/programgarden_core/bases/listener.py` โ `ExecutionListener`
callback contract
- `src/programgarden/examples/workflows/` โ 77 runnable workflow JSON files
(start with `01-account-stock-balance.json`)
- `src/community/programgarden_community/plugins/rsi/__init__.py` โ canonical
plugin shapeLS์ฆ๊ถ API ์ง์ ์ฌ์ฉ์์ฉ (programgarden-finance ๋จ๋
)
์ํฌํ๋ก์ฐ ์์ง ์์ด LS์ฆ๊ถ OpenAPI ๋ํผ๋ง ์ฌ์ฉํด ์์ ์ ์คํฌ๋ฆฝํธ์์ TR(๊ฑฐ๋์ฝ๋)์ ์ง์ ํธ์ถํ ๋ ์ฌ์ฉํฉ๋๋ค. ์๋ ๋ธ๋ก์ ํต์งธ๋ก ๋ณต์ฌํด ์์ด์ ํธ์๊ฒ ๋ถ์ฌ ๋ฃ์ผ์ธ์.
# ProgramGarden Finance โ Direct LS Securities API Context
You are helping a user of the `programgarden-finance` library
(https://pypi.org/project/programgarden-finance/). They are calling LS Securities
OpenAPI TRs directly through their own scripts, without the workflow engine.
Follow this context strictly.
## What this library is
- A typed sync/async wrapper over LS Securities OpenAPI. Each TR (e.g.
`t1410`, `t8407`) is a Pydantic `blocks.py` module exposing
`InBlock` / `OutBlock` types. The TR class itself exposes both `.req()`
(sync) and `.req_async()` (async) callers.
- Coverage: ~150 TR blocks across Overseas Stock / Overseas Futures / Korea
Stock REST, plus ~28 real-time WebSocket TR blocks (7 overseas stock +
7 overseas futures + 13 Korea stock + 1 shared).
- TR layout:
`src/finance/programgarden_finance/ls/{market_segment}/{kind}/t####/` โ
every TR has its own folder; `blocks.py` defines all fields with
`Field(title=..., description=..., examples=[...])`.
- Authentication: `appkey` + `appsecret` from the LS Securities developer
portal. Token refresh and rate-limit handling are built in.
- Source-of-truth rule: the library never asserts LS-undocumented formulas,
sign conventions, units, or time-series ordering. If LS spec doesn't say it,
the field description literally says `"Not declared in available source."`
Respect this โ do not infer.
## Prompt templates
### Call a single TR
```
Using `programgarden_finance`, write a script that calls Korea Stock TR
`t1410` (์ด์ ์ ๋์ฑ์กฐํ / ultra-low-liquidity query).
See `src/finance/example/korea_stock/run_t1410.py` for the canonical calling
convention (both `.req()` and `.req_async()` patterns).
Read `appkey` / `appsecret` from env vars `LS_APPKEY` / `LS_APPSECRET`.
```
### Find the right TR
```
I need to fetch minute-bar OHLCV for a Korea stock. Browse
`src/finance/programgarden_finance/ls/korea_stock/` to find the right TR,
read its `blocks.py` to understand the InBlock / OutBlock fields
(`src/finance/programgarden_finance/ls/korea_stock/market/t1410/blocks.py` is
a canonical reference for field metadata structure), then write a runnable
example modeled after the matching
`src/finance/example/korea_stock/run_t####.py`.
```
### Real-time subscription
```
Subscribe to Korea Stock real-time price ticks using `programgarden_finance`.
Use the singleton WebSocket pattern from
`src/finance/programgarden_finance/ls/real_base.py`. See
`src/finance/example/korea_stock/real_S3_.py` for a complete subscription
example. Print each tick as it arrives and handle reconnect cleanly.
```
## Gotchas โ call these out up front, they trip agents constantly
1. Don't invent field semantics. If the description says
`"Not declared in available source"`, do not derive a formula or unit โ
ask the user instead.
2. Rate limits are per-TR and enforced by the library. Don't hand-roll your
own throttling on top.
3. WebSocket is a singleton per credential โ don't open multiple connections;
add subscriptions to the existing session.
4. Field `title` / `description` / `examples` are AI-chatbot ground truth for
every TR. When editing `blocks.py`, preserve all three.
5. Korean stock uses `shcode` (6 digits); overseas stock uses
`symbol` + `exchange`. They are not interchangeable.
## Reference files to read before answering
- `src/finance/example/` โ runnable per-TR samples (overseas stock / futures /
Korea stock)
- `src/finance/programgarden_finance/ls/real_base.py` โ singleton WebSocket
pattern for all real-time subscriptions
- `src/finance/programgarden_finance/ls/korea_stock/market/t1410/blocks.py` โ
canonical TR `blocks.py` to mirror when adding or studying a TR
- LS Securities OpenAPI portal: https://openapi.ls-sec.co.kr/apiservice