OpenAlice 설치부터 실전까지 — 내 에이전트에게 시장 도구와 거래 계좌를 쥐여 주는 오케스트레이터

OpenAlice 는 자기 모델을 갖지 않고 여러분이 쓰던 에이전트를 데려옵니다. 76개 툴을 실제로 세어 보고, 주문이 사람 승인 앞에서 멈추는 것을 확인하고, 그 판단을 weltiq 전략 컨테이너에 옮겨 한 바퀴 돌렸습니다.

16편. OpenAlice — 내 에이전트에게 시장 도구와 거래 계좌를 쥐여 주는 오케스트레이터

이 글의 완료 조건: 독자는 브로커 계정 없이 OpenAlice 를 띄워 에이전트가 낸 주문이 사람 승인 앞에서 멈추는 것을 보고, 그 판단을 weltiq 전략 컨테이너로 옮겨 왕복 체결까지 받으면 성공입니다.

하는 일 자기 모델 없이 여러분이 이미 쓰는 에이전트(Claude Code·Codex 등)를 데려와 시장 데이터·리서치 작업공간·거래 계좌를 툴 76개로 쥐여 줍니다
맞는 사람 에이전트를 이미 쓰고 있고, 특히 "에이전트가 뭘 하자고 했는지"를 기록으로 남기고 싶은 사람
안 맞는 사람 체결 비용·유동성에 민감한 전략을 이 도구의 시뮬레이터로 검증하려는 사람 · 사람이 자리를 비운 채 무인 반복을 돌리려는 사람
이 글의 결과물 76개 툴이 붙은 로컬 작업공간, 승인 앞에서 멈춘 주문 한 건, 그 판단으로 만든 규칙이 weltiq 에서 낸 왕복 체결 기록
준비물·비용 코드 0원(AGPL-3.0) · 모델 에이전트의 LLM 호출 · 시세 0원, 키 0개 · 브로커 계정 0개
시간·난도 받고 까는 데 33.6초, 화면까지 5분. 난도 중 — 환경변수 두 개와 빌드 한 줄
weltiq 와의 관계 판단과 근거가 들어오고 실행이 나갑니다. 에이전트가 낸 규칙을 weltiq 로 옮겨 상주로 돌리고, 그 기록을 다시 물려 고리를 한 바퀴 돌렸습니다(5절)
검증 환경·날짜 macOS 26.6.2 · arm64 · Node 26.8.1 · pnpm 11.7.0 · OpenAlice 0.94.1-beta · 2026-09-22 01:44~02:16 KST
제휴 고지 필자는 weltiq 로부터 이 연재의 원고료를 받습니다. 도구 평가는 필자가 직접 돌린 결과만 씁니다

사람 쪽 문장은 실제로 친 명령을 대화로 옮긴 것이고, 출력은 실측이며 숫자는 손대지 않았습니다. 주문은 전부 모의입니다 — OpenAlice 쪽은 내장 시뮬레이터, weltiq 쪽은 페이퍼. 브로커 계정을 하나도 연결하지 않았고 어떤 매매 의견도 아닙니다. 원문 로그는 검증 기록에 있습니다.


1. 이게 뭔가요

먼저 어느 저장소인지부터 밝힙니다. 같은 이름의 저장소가 여럿(2021년 C++ 게임, 개인 비서 프로젝트 등) 있어 GitHub 검색으로 확인한 뒤 TraderAlice/OpenAlice 로 정했습니다. 자기 소개는 "Your one-person Wall Street — 여러분의 AI 에이전트, 시장 도구, 리서치, 거래 계좌를 하나의 로컬 작업공간으로." 구조가 이 글 내내 중요하니 세 조각으로 나눠 둡니다.

조각 무엇인가
Alice 본체. 시장 데이터·뉴스·펀더멘털·리서치 작업공간·일정을 관리하고, 그걸 MCP 서버로 내놓습니다
UTA (Unified Trading Account) 브로커 추상화 계층. CCXT·Alpaca·IBKR·LeverUp·Longbridge 가 별도 Broker Pack 으로 붙고, 내장은 Mock 시뮬레이터 하나뿐입니다
Trading as Git 주문을 git 처럼 다룹니다 — add(스테이징) → commit(근거를 메시지로) → push(집행). 그리고 push 는 기본적으로 사람 승인을 요구합니다

판단하는 자리에 있는 것은 이 저장소의 코드가 아니라 이 저장소가 쥐여 준 툴을 쓰는 여러분의 에이전트입니다. OpenAlice 자신은 도구를 모으고, 기록을 남기고, 주문이 나가기 전에 사람 앞에 세웁니다.

항목 값 확인 방법
주소 github.com/TraderAlice/OpenAlice
라이선스 AGPL-3.0 GitHub API
별 수 ★7,125 · 포크 1,133 (관측일 2026-09-22) GitHub API
마지막 푸시 2026-09-20 GitHub API
개설 2026-02-18 · 열린 이슈 77 · 아카이브 아님 GitHub API
버전 0.94.1-beta · 언어 TypeScript package.json
규모 워크스페이스 패키지 11 + 서비스 2, .ts 파일 2,129개 ls · find
툴 수 76개 3절에서 직접 셉니다

AGPL-3.0 은 짚고 갑니다. 개인이 자기 노트북에서 쓰는 데는 문제가 없지만, 고쳐서 남에게 서비스로 제공하시려면 소스 공개 의무가 따라옵니다. README 가 스스로 적어 둔 경고도 그대로 옮깁니다 — 이 글이 페이퍼만 쓰는 근거이기도 합니다.

Trading execution is beta. Start with simulator, paper, demo, or testnet accounts. OpenAlice is experimental software; it provides no guarantees of correctness, reliability, profitability, or loss prevention.


2. 설치

준비물은 셋 — Node.js 22.19 이상(필자는 26.8.1), pnpm 11.7.0(npx pnpm@11.7.0 로 그냥 써도 됩니다), 0원. 데스크톱 앱 릴리스가 정식 경로지만 안을 들여다보려고 소스로 띄웠습니다.

git clone --depth 1 https://github.com/TraderAlice/OpenAlice.git
cd OpenAlice
npx --yes pnpm@11.7.0 install

실측으로 clone 5.081초(저장소 84MB), install 28.472초(설치 후 1.2GB · node_modules/.pnpm 1,055개) — 받고 까는 데 33.6초입니다. 다만 이 상태로 pnpm dev 를 하면 웹 UI 가 안 뜹니다([vite] Failed to resolve entry for package "@traderalice/connector-protocol"). 워크스페이스 내부 패키지가 아직 빌드되지 않아서이고, 한 줄 더 치면 됩니다(실측 4.543초). 그리고 기본값 두 개를 바꿔야 거래 쪽이 열립니다 — 필자가 제일 오래 헤맨 자리입니다.

# ① 워크스페이스 패키지 빌드 (한 번만)
npx --yes pnpm@11.7.0 -F @traderalice/connector-protocol -F @traderalice/uta-protocol \
  -F @traderalice/opentypebb -F @traderalice/ibkr -F @traderalice/guardian-runtime build

# ② 거래 모드 pro (안 주면 lite 로 떠서 UTA 가 기동하지 않습니다)
#   + data/config/mcp.json 의 enabled 를 true 로 (기본 false)
OPENALICE_HOME=~/.openalice OPENALICE_TRADING_MODE=pro \
OPENALICE_WEB_PORT=9050 OPENALICE_MCP_PORT=9051 OPENALICE_UTA_PORT=9052 \
OPENALICE_UI_PORT=9054 npx --yes pnpm@11.7.0 dev

이렇게 나오면 성공입니다. (포트를 박은 것은 그 기계에서 다른 것들이 돌고 있어서고, 안 박으면 알아서 빈 포트를 찾습니다.)

[guardian] mode  →  pro (env, env-locked)   [guardian] UTA →  http://127.0.0.1:9052
[guardian] Alice →  http://localhost:9050   [guardian] MCP →  http://127.0.0.1:9051/mcp
[guardian] UI    →  http://localhost:9054
[alice] tool-center: 76 tools registered

Guardian 이 부모고 그 아래에 Alice·UTA·에이전트 세션들이 각자 프로세스로 뜹니다. 하나가 죽어도 Guardian 이 되살립니다.

OpenAlice 첫 기동 화면

브라우저로 http://localhost:9054 를 열면 나오는 첫 화면입니다. 왼쪽 사이드바에 Market·Trading 이 보이면 OPENALICE_TRADING_MODE=pro 가 먹은 겁니다 — lite 로 뜨면 Trading 항목 자체가 없습니다. 가운데 "Initialize Ask Alice" 는 대화용 작업공간을 처음 한 번 만드는 버튼이고, 이 글에서는 누르지 않았습니다.

막히는 자리

증상 원인 해결
웹 UI 가 vite 오류 화면 워크스페이스 패키지 미빌드 위의 -F … build 한 줄. 한 번만 하면 됩니다
사이드바에 Trading 이 없다 OPENALICE_TRADING_MODE 미설정 → lite pro 로 주고 재기동
/mcp 가 404 data/config/mcp.json 의 enabled: false true 로 고치고 재기동
포트가 매번 바뀐다 기본은 빈 포트 탐색 OPENALICE_*_PORT 를 박거나 data/config/ports.json
브라우저에 404 주소가 넷입니다 — 화면 9054, API 9050, 거래 9052, MCP 9051 기동 로그의 UI → 줄이 답입니다
브로커가 안 보인다 라이브 브로커 SDK 는 별도 Broker Pack 이고 본체에 없습니다 이 글에서는 내장 mock-simulator 만 씁니다

3. 첫 결과

대시보드가 본체이고 로그인은 없습니다 — 로컬 루프백에 바인딩되고 계정 자체가 없습니다(첫 기동 때 콘솔에 찍히는 admin 토큰은 원격 접속용입니다). 시세·차트·펀더멘털·뉴스까지 키 없이 보입니다. 키가 필요한 것은 에이전트의 모델 자격증명과 실브로커 키 둘뿐이고, 이 글은 둘 다 안 씁니다.

처음 열면 빈 화면이고 쓸 만한 화면까지 가는 길은 둘입니다. Market 에서 티커를 치면 차트·펀더멘털·뉴스가 바로 나오고, Trading 에서 계좌를 하나 만들면 Portfolio 와 Trading as Git 이 살아납니다. 브로커 계정이 없어도 내장 mock-simulator 로 만들 수 있습니다.

Trading → All Accounts, 시뮬레이터 계좌 하나

Trading 을 누르고 계좌를 하나 만들면 나오는 화면입니다. 가운데 "Total Equity (USD) $10,000.00" 가 방금 만든 시뮬레이터 계좌이고, 아래 "No open positions." 가 정상입니다. 왼쪽 두 번째 칸의 "Trading as Git" 옆 빨간 배지 1 을 보세요 — 승인을 기다리는 커밋이 하나 있다는 뜻이고, 4절에서 이 화면으로 돌아옵니다. 오른쪽 아래 Snapshots 토글은 계좌 스냅숏 주기(기본 15분)입니다.

제일 작은 예제는 툴이 몇 개 붙었는지 세어 보는 것입니다. 이 도구의 값은 결국 "내 에이전트가 무엇을 쓸 수 있게 되는가"니까요.

이렇게 말합니다

OpenAlice MCP 에 붙어서 툴 목록 좀 보여 줘.

그러면 이런 게 돌아옵니다 (76개 중 이름만, 묶어서 줄였습니다)

server: open-alice 1.0.0   tools: 76

거래(25)   listUTAs getAccount getPortfolio getOrders getOrderBook getQuote
           placeOrder modifyOrder closePosition cancelOrder
           tradingLog tradingShow tradingStatus tradingCommit tradingPush tradingReject tradingSync
시장(14)   marketSearchForResearch searchBars getMarketBars marketSnapshot calculateQuant
           marketGetBoard sectorRotation cryptoFuturesInstruments setMarketVendor
기업(8)    equityGetProfile equityGetFinancials equityGetRatios equityGetEarningsCalendar
           equityGetInsiderTrading equityGetShortInterest equityGetEstimates equityDiscover
ETF·뉴스(8) etfSearch etfGetInfo etfGetHoldings etfGetSectors  globRss grepRss windowRss readRss
거시(20)   economyFredSearch economyFredSeries economyBlsSeries economyFomcDocuments …

76개 중 상태를 바꾸는 것은 7개뿐입니다 — placeOrder modifyOrder closePosition cancelOrder tradingCommit tradingPush tradingReject. 나머지 69개는 읽기이고, 이 비율이 이 도구의 성격입니다.

이제 계좌를 하나 만듭니다. 브로커 계정은 필요 없습니다.

{"id":"mock-simulator-efe8abb4","presetId":"mock-simulator","presetConfig":{"cash":10000}}
listUTAs   → capabilities {"supportedSecTypes":["STK","CRYPTO"],
                           "supportedOrderTypes":["MKT","LMT","STP","STP LMT"]}
             health {"status":"healthy","reach":"readable","tier":"trading"}
getAccount → {"netLiquidation":"10000","totalCashValue":"10000","realizedPnL":"0"}

이렇게 나오면 성공입니다. health.status 가 healthy 고 현금이 10,000 이면 준비 끝입니다.

직접 치고 싶다면
curl -s http://127.0.0.1:9050/api/trading/config/broker-presets | python3 -m json.tool
curl -s -X POST http://127.0.0.1:9050/api/trading/config/uta \
  -H 'Content-Type: application/json' \
  -d '{"presetId":"mock-simulator","label":"weltiq-blog-sim","presetConfig":{"cash":10000}}'
MCP 쪽은 `127.0.0.1:9051/mcp` 에 Streamable HTTP 로 `initialize` → `tools/list` → `tools/call` 을 주고받으면 됩니다.

이 글의 실행은 OpenAlice 안에서 Claude Code 를 기동하는 대신 그 MCP 표면에 OpenRouter 모델(openai/gpt-5.6-luna)을 붙여서 했습니다. 에이전트가 보는 툴과 받는 응답은 같지만 똑같은 조건은 아니라는 점을 밝혀 둡니다.


4. 제일 잘 쓰는 법 — 주문을 스테이징만 하고 사람이 승인하기

제일 잘 쓰는 법을 하나 고른다면 Trading as Git 입니다. 에이전트가 placeOrder 를 불러도 주문이 나가지 않고 git 의 add 처럼 스테이징만 됩니다 — 툴 설명에 그렇게 적혀 있습니다("Stage an order (will execute on tradingPush)").

이렇게 말합니다

AAPL 10주 시장가로 사고, 왜 샀는지 커밋 메시지에 적어서 올려 줘.

그러면 이런 게 돌아옵니다 (네 번의 호출을 한 칸에 모았습니다)

placeOrder     → {"staged": true, "index": 0,
                  "operation": {"action":"placeOrder","symbol":"AAPL",
                                "order":{"action":"BUY","orderType":"MKT","totalQuantity":"10"}}}
tradingCommit  → {"prepared": true, "hash": "bcc0e8ab",
                  "message": "weltiq blog A16: stage 10 AAPL to observe the approval gate"}
tradingPush    → {"message": "Push requires manual approval (AI trading is disabled).
                              Tell the user to review and approve the pending operations
                              in the Web UI (Trading as Git page, or the account detail page)."}

여기서 멈춥니다. 주문은 아직 한 건도 나가지 않았습니다.

Trading as Git — 승인을 기다리는 커밋

에이전트가 tradingPush 를 부른 직후의 화면입니다. 왼쪽 위 "1 commit waiting for approval" 과 카운터 1 Needs / 0 Staged / 2 Pushed, 오른쪽의 Needs approval 배지와 Approve & Push / Reject 두 버튼이 이 도구의 핵심입니다. 가운데 "Operation diff" 는 승인하면 나갈 주문 한 건(BUY AAPL · MKT → qty 10)이고, 아래 빨간 상자가 경고문입니다 — "Approval pushes these operations to the broker account. Check account, side, quantity, and order type before confirming." 에이전트는 여기까지만 올 수 있고, 이 두 버튼은 사람 몫입니다.*

코드로 확인하면 스위치 하나이고 기본값이 꺼짐입니다(allowAiTrading: z.boolean().default(false)). 켜려면 Settings → Agent Permissions 에서 사람이 이중 확인을 거쳐야 합니다. 필자는 이 글에서 끝까지 켜지 않았습니다.

이제 사람 자리에서 승인합니다.

POST …/wallet/push   (본문 없이)
→ 409 {"error": "expectedPendingHash is required", "code": "PENDING_HASH_REQUIRED"}

POST …/wallet/push   {"expectedPendingHash": "bcc0e8ab"}
→ 200 {"hash": "bcc0e8ab", "submitted": [{"status": "filled", "orderId": "mock-ord-1"}]}

"대기 중인 것 아무거나 승인" 이 안 됩니다. 내가 본 그 커밋의 해시를 같이 보내야 합니다 — 읽은 것과 승인한 것이 같다는 보장이 프로토콜에 박혀 있습니다. 체결 결과도 적어 둡니다.

체결 직전 호가  bid 99.99 | ask 100.01 | last 100
체결           AAPL 10주 @ 100.00   status filled
계좌           cash 10000 → 9000   netLiquidation 10000 (그대로)
commissionAndFees  1.7976931348623157e+308   ← IBKR 의 "미설정" 센티넬

내장 시뮬레이터는 수수료도 스프레드도 없습니다. 매수인데 ask 100.01 이 아니라 last 100.00 에 붙었고 netLiquidation 이 1센트도 안 줄었습니다. 비판이 아니라 눈금 이야기입니다 — 프리셋 설명도 "For UI/AI repro testing only" 라고 적고 있습니다.

거절도 해 봤습니다. tradingReject 는 {"hash":"b39f9859","message":"[rejected] BTCUSDT 1m long-only: …"} 를 돌려줍니다. 거절한 결정이 지워지지 않고 [rejected] 접두어가 붙어 로그에 남습니다.

Trading as Git — 거절된 커밋의 상세

Trading → Trading as Git 화면입니다. 왼쪽 목록의 b39f9859 가 에이전트가 올린 커밋이고, 오른쪽 본문이 에이전트가 직접 쓴 근거 전문입니다(SMA20 85846.32, SMA50 85829.37, RSI14 56.41 같은 숫자가 그대로 들어 있습니다). 가운데 "Operation diff" 의 BUY BTCUSDT user rejected 를 보세요 — 사람이 거절했다는 사실까지 diff 에 남습니다. 왼쪽 위 0 Needs / 0 Staged / 2 Pushed 가 현재 스테이징 상태입니다.

끊고 다시 붙이면 — 결정 기록은 살고 포지션은 죽습니다

AAPL 10주를 사 둔 채로 프로세스를 전부 죽이고 다시 띄웠습니다.

재시작 전   positions [{"symbol":"AAPL","quantity":"10","avgCost":"100"}] · cash 9000
재시작 후   positions []                                                 · cash 10000
wallet/log  커밋 1건 (bcc0e8ab)  ← 앞뒤로 그대로

커밋 로그는 git 으로 디스크에 남고, 시뮬레이터의 포지션과 현금은 프로세스 메모리에 있어 초기값으로 돌아갑니다. 버그가 아니라 프리셋 설명에 미리 적힌 성질입니다 — "everything is wiped on dev server restart." 다만 시뮬레이터로 며칠짜리 전략을 확인하려던 계획이라면 여기서 멈추셔야 합니다. 실브로커를 붙이면 상태가 브로커 쪽에 있어 이 문제가 없지만, 이 글은 브로커를 안 썼으므로 실브로커 연결 상태에서의 복구는 미확인입니다.

재시작 직후의 Trading → Overview

재시작 직후 같은 화면입니다. 위쪽 Total Equity $10,000.00 · Cash $10,000.00 · "No open positions." — 사 둔 AAPL 10주가 사라지고 현금이 초기값으로 돌아갔습니다. 그런데 아래 Recent Trades 에는 커밋 두 건이 그대로 남아 있습니다(b39f9859 와 bcc0e8ab, 근거 문장까지). 포지션은 죽고 결정 기록은 사는 것이 이 화면 한 장에 같이 나옵니다.

함정 — 없는 심볼을 만들어 줍니다

2차 판단에서 에이전트가 실제로 밟은 자리라 따로 적습니다. calculateQuant 로 시뮬레이터 계좌의 봉을 부르면 어떤 문자열이든 봉이 나옵니다.

bars("mock-simulator-…|BTCUSD", "1m", count=500)
→ {"value": [149.9, 148.95, 147.45]}   ← 비트코인 가격이 아닙니다
   dataRange from 2025-05-10 … to 2026-09-21, bars 500, interval "1m"
                                       ← "1분봉 500개" 인데 구간이 16개월입니다
bars("mock-simulator-…|ZZZNOTREAL", "1m", count=10)
→ {"value": [100.9]}  isLatestActual true  barCapability "realtime"
                                       ← 존재하지 않는 심볼인데 오류 없이 봉을 만들어 줍니다

marketSnapshot("BTC")     → barId yfinance|BTC   close 38.02   ← 미국 상장 티커 'BTC'
marketSnapshot("BTC-USD") → barId yfinance|BTC-USD             ← 이게 비트코인

재는 자를 잘못 집을 수 있다는 이야기입니다. 오류도 경고도 없이 합성된 숫자가 돌아오니 리서치 때는 barId 를 눈으로 확인하십시오.

반대쪽도 적어야 공평합니다. 실제 시세 툴은 이 연재에서 본 것 중 제일 정직합니다. BTC-USD 90봉을 부르면 봉 밑에 자기가 지연을 모른다는 문단이 붙어 나오고("actual delay is unknown"), 한국 종목은 005930.KS 로 불러야 잡히는데 9월 21일 자료의 close 가 비어 있어 버렸다고 적으면서 isLatestActual: false · staleTradingDays: 1 을 못 박습니다.

OpenAlice Market 화면의 BTCUSD 차트

BTC-USD 로 검색해서 Bitcoin USD 를 연 화면입니다. 오른쪽 위 "366 bars · 2025-09-21 — 2026-09-21" 과 심볼 옆 delayed 배지를 보세요 — 어느 구간을 어느 출처로 보고 있는지가 차트 위에 붙어 있습니다. 그리고 왼쪽 검색 결과 맨 위에 AAPL / mock-simulator 가 올라와 있는 것도 같이 보세요. 시뮬레이터 계좌가 시세 공급자로 등록돼 있어서 "BTC-USD" 검색에 AAPL 이 끼어듭니다.


5. weltiq 로 옮기기

OpenAlice 의 산출물은 주문 하나가 아니라 "규칙 + 근거" 입니다. 커밋 메시지에 근거가 있고 스테이징된 오퍼레이션에 숫자가 있습니다.

사람이 옮기는 순서

① 규칙 문서로 쓴다   POST /v1/strategy-rules
② 근거를 내 말로 쓴다  POST /v1/ai/thesis
③ 중지 조건을 건다    POST /v1/containers (stop_max_loss · stop_after_hours 필수)
④ 돈다              무인. 사람도 OpenAlice 도 꺼져 있어도 컨테이너가 규칙을 지킵니다

②와 ③은 건너뛸 수 없습니다 — 빼고 던지면 {"code":"thesis_required"} 와 세 질문이, 또는 {"loc":["body","stop_max_loss"],"msg":"Field required"} 가 돌아옵니다.

스테이징된 주문 한 건을 weltiq 의 1회성 주문으로 옮기는 경로는 막혔습니다 — POST /v1/orders/oneoff 가 422 envelope_required 를 내고, 그 승인을 만드는 POST /v1/envelopes 는 403 session_required(API 키 불가)입니다. weltiq 의 1회성 주문에도 사람 승인이 앞에 섭니다. 그래서 규칙을 옮기는 경로로 갔습니다. 양쪽이 같은 모양의 문을 갖고 있습니다 — OpenAlice 는 tradingPush 앞에, weltiq 는 orders/oneoff 앞에.

제일 나은 조합 — 승인은 한 번만, 재는 일은 weltiq 에서

누가 무엇을
OpenAlice 자료를 모으고, 에이전트가 판단하고, 커밋 메시지로 근거를 박는다
사람 그 커밋을 읽고 승인/거절한다. 승인한 것만 weltiq 문서로 옮긴다
weltiq 비용·체결이 있는 곳에서 상주로 돌리고 기록을 낸다
다시 OpenAlice 그 기록 원문을 받아 다시 판단한다

allowAiTrading 을 켜서 자동 집행하게 하는 대신 커밋을 사람이 읽는 자리로 쓰는 것입니다. 이유는 4절에서 재 본 그대로 — 내장 시뮬레이터는 수수료 0·스프레드 0이라 비용을 재는 자가 아닙니다.

실제로 옮겼습니다. 미션은 "비트코인을 거래해서 수익을 내줘. 진입 규칙과 청산 규칙을 숫자로 정하고, 왜 그렇게 했는지도 설명해줘." 한 문장이었고, 사람이 한 일은 그 문장과 목적지 문법의 사실(블록 이름·인자, "롱 전용·무레버리지")을 알려 준 것뿐입니다. 종목·방향·숫자는 고르지 않았습니다.

"20/50 SMA crossover는 1분봉의 매우 짧은 잡음을 일부 줄이면서 단기 상승 추세를 추종하도록 선택했다. 1.5% trailing stop은 정상적인 1분봉 변동에는 어느 정도 여유를 주면서도 추세 반전 시 손실을 제한하기 위한 설정이다. 0.01 BTC는 당시 가격 기준 약 859달러의 명목금액으로, 10,000달러 paper 계정에서 과도한 노출을 피하기 위해 정했다." — 에이전트의 출력 원문 (2026-09-22 02:06 KST)

에이전트가 낸 것 weltiq 쪽 문서 옮겨졌나
sma_cross(fast 20, slow 50) crossover(sma(close,20), sma(close,50)) 그대로
trailing_stop(1.5) managed_exit(trailing_pct "1.5") 그대로
fixed_qty 0.01 fixed_qty qty "0.01" 그대로
— managed_exit(stop_pct …) 빈칸이었습니다

네 번째 칸이 이 편의 정직함 대목입니다. weltiq 문법은 추적 손절과 별도로 보호 손절 퍼센트를 요구하는데 에이전트는 그 칸을 주지 않았습니다. 근사하지 않고 되물었고, 답은 {"stop_pct":"1.0","why":"A 1.0% hard stop limits adverse loss while leaving the 1.5% trailing stop room to follow normal short-term volatility."} 였습니다.

weltiq 내 전략 목록 — 옮겨진 두 문서

weltiq 의 「My strategies」 화면입니다. 두 줄을 보세요 — 에이전트가 낸 숫자가 weltiq 쪽 규칙 문장으로 바뀌어 있습니다. 1차는 sma(close, 20)/sma(close, 50) · 추적 1.5%, 2차는 sma(close, 30)/sma(close, 80) · 추적 2.0% 입니다. 오른쪽의 1/100 은 이 문서로 시행한 횟수입니다. 계정 식별자는 가렸습니다.

같은 문서를 비용 있는 곳에 놓으면

굳은 문서를 weltiq 봉으로 30일 리플레이했습니다 — binance-spot BTCUSDT 1분봉 43,188봉, 체결 75건·왕복 37회에 실현손익 −16.40950921, 수수료 58.61362146(거절 0건). 수수료가 총손실의 3.6배입니다. 요율을 바꿔 봐도 달라지는 게 없었습니다 — 같은 체결을 다른 거래소 규칙으로 다시 계산하니 binance-spot 과 bybit-spot 이 둘 다 0.1% 정액이라 delta 0E-8 이었습니다. 이 전략에서 비용을 움직이는 축은 요율이 아니라 왕복 횟수입니다.

고리를 한 바퀴 돌렸습니다

테두리를 치고(BTC 현물, 자본 1만, 누적 손실 200 에서 중지, 2시간 뒤 자동 종료) 컨테이너를 올린 뒤 중지 조건을 실제로 건드려 봤습니다.

PATCH …/limits {"stop_max_loss":"20"}
→ 200 {"changed":{"max_loss":{"from":"200","to":"20","direction":"tighten"}}}
PATCH …/limits {"stop_max_loss":"500"}
→ 403 {"code":"session_required",
       "detail":"한도를 늘리는 것은 로그인 세션에서만 할 수 있습니다 (줄이는 것은 API 키·MCP 로도 됩니다)"}

조이는 것은 되고 늘리는 것은 안 됩니다. allowAiTrading 게이트와 짝을 이루는 자리입니다 — 저쪽은 "집행 전에 사람", 이쪽은 "한도 확대는 사람". 시간 한도를 앞당겨 실제로 발동시키기도 했습니다(autostop {"reason":"expired","cumulative_pnl":"-0.08602147500"} → stopped).

그 컨테이너에서 진짜 왕복이 한 번 났습니다. 진입은 규칙이, 청산은 종료 조건이 냈습니다.

BUY  0.005 BTCUSDT @ 85980.07714750  fee 0.42990039  taker  (기대가 85971.48)  02:04:00
SELL 0.005 BTCUSDT @ 85962.87285250  fee 0.42981436  taker  (기대가 85971.47)  02:06:00
realized_pnl -0.08602147500 · fees 0.85971475
equity 10000 → 9999.05426378  (-0.0095%)

체결가가 기대가에서 양쪽 다 8.597 USDT 씩 벌어졌습니다. 살 때는 위로 팔 때는 아래로 정확히 같은 폭 — 모델링된 스프레드의 절반씩이고 1.0bp 입니다. 4절의 "호가 무시하고 last 에 체결"과 나란히 놓으면 두 계측기의 눈금 차이가 보입니다.

weltiq 체결 내역

weltiq 의 「History」 화면입니다. 가운데 02:04:00 buy 0.005 @ 85,980.08 / 02:06:00 sell 0.005 @ 85,962.87 두 줄이 이 글에서 난 왕복입니다. 수수료 칸(0.430)과 taker 표시, 그리고 Binance spot · weltiq paper 라는 출처가 줄마다 붙어 있는 것을 보세요. 위쪽 backtest 배지가 붙은 줄은 리플레이 체결이라 구분됩니다. 계정 식별자는 가렸고, "Effective rate NaN %" 는 실제로 그렇게 나온 화면입니다 — 손대지 않았습니다.

30일 리플레이 결과 원문과 컨테이너 내보내기 원문을 가공 없이 에이전트에게 되돌려주고 다시 판단받았습니다.

"이전 20/50 SMA 교차 전략은 30일 리플레이에서 37회 거래를 발생시켰고 총 손익 -16.4095, 수수료 58.6136으로 과도한 매매와 수수료 부담을 보였습니다. 30/80으로 늦춰 같은 추세추종 구조를 유지하면서 1분봉 잡음을 줄이도록 했습니다. trailing stop은 1.5%에서 2.0%로 넓혀 작은 되돌림에 의한 조기 청산을 완화했습니다. 손실 전략을 수정하는 테스트 단계이므로 수량은 0.01 BTC에서 0.005 BTC로 절반 축소했습니다." — 에이전트의 출력 원문 (2026-09-22 02:10 KST)

고친 숫자(20/50 → 30/80, 추적 1.5% → 2.0%, 보호 손절 1.0% → 3.0%, 수량 0.01 → 0.005 BTC)로 문서를 다시 만들어 제출하고 새 컨테이너를 올렸습니다. 바로 위의 왕복이 그 컨테이너에서 난 일입니다. 고리가 닫혔습니다. 같은 30일을 다시 리플레이해 두 문서를 나란히 놓았습니다.

1차 (20/50, 추적 1.5%, 0.01) 2차 (30/80, 추적 2.0%, 0.005)
봉 43,188 43,188
체결 75 39
왕복 37 19
실현손익(총) −16.40950921 −3.98620772
수수료 58.61362146 15.22453619
순 −75.02313067 −19.21074391

둘 다 마이너스입니다. 수익을 냈다는 이야기가 아닙니다. 달라진 것은 비용의 크기고, 그걸 에이전트가 weltiq 기록을 보고 스스로 줄였다는 점입니다. 다만 왕복이 절반(37→19)이 되고 수량도 절반(0.01→0.005)이 됐으니 수수료 감소(−74%)는 두 효과가 곱해진 결과입니다 — 왕복당 수수료는 1.584 → 0.801 로 정확히 수량 비율만큼 줄었습니다. 그리고 이 한 번의 30일 구간이 무엇도 증명하지 않습니다. 확인된 것은 "되먹임이 돌았다"이지 "고친 쪽이 낫다"가 아닙니다.

벽 하나. 2차 판단에서 에이전트가 새 주문을 스테이징하려다 Error: A commit is awaiting approval. Push or reject it before staging more operations. 로 막혔습니다. 사람이 승인도 거절도 안 한 커밋이 하나 있으면 그다음이 통째로 멈춥니다. 버그가 아니라 설계이지만, 무인으로 돌리실 생각이라면 알고 계셔야 합니다.

이 조합이 해 주지 않는 것: 결과를 OpenAlice 쪽에 자동으로 반영시킬 방법은 없고, Trading-as-Git 로그와 weltiq 저널은 서로를 모릅니다. 실전 구간도 아직 닫혀 있습니다(live_orders: false) — "같은 문서가 백테스트와 페이퍼를 같은 몸으로 지나간다"까지가 사실이고 그 뒤는 예정입니다.


6. 써 보니

좋았던 것

  1. 주문이 사람 앞에서 멈춥니다. allowAiTrading 기본값이 꺼짐이고, push 하면 "사람에게 승인받으라"가 돌아옵니다. 이 게이트를 기본으로 켜 둔 도구는 손에 꼽습니다
  2. 승인이 해시로 잠깁니다. expectedPendingHash 없이는 409 입니다. 거절한 결정도 [rejected] 접두어가 붙을 뿐 지워지지 않습니다
  3. 근거가 커밋 메시지라는 발상이 좋습니다. 판단과 이유가 한 덩어리로 타임스탬프와 함께 박힙니다 — 되먹임을 돌리기에 이보다 좋은 출력 형태가 없습니다
  4. 자기가 모르는 것을 응답에 적습니다. 지연을 모른다, 이 봉은 최신이 아니다, 이 행은 OHLC 가 비어서 뺐다. 그리고 브로커 계정 없이 끝까지 해 볼 수 있습니다

아쉬웠던 것

  1. 내장 시뮬레이터가 없는 심볼을 만들어 줍니다. ZZZNOTREAL 에도 봉이 나오고 isLatestActual: true 가 붙습니다. 리서치 툴이 조용히 합성 숫자를 물려주는 것은 위험합니다
  2. 그 시뮬레이터에 수수료도 스프레드도 유동성 제약도 없습니다. 게다가 그 계좌가 asVendor 로 시세 공급자 목록에 올라가 리서치에 섞이고, 재시작하면 포지션이 전부 사라집니다
  3. 기본값 두 개가 조용히 꺼져 있고(OPENALICE_TRADING_MODE·mcp.enabled), 설치 직후 pnpm dev 로 웹 UI 가 안 뜹니다. 셋 다 README 에 그 줄이 없습니다
  4. 승인 대기 하나가 다음 판단을 막습니다. 그리고 AGPL-3.0 이라 서비스로 내놓을 계획이면 라이선스를 먼저 읽으셔야 합니다

비용

항목 값
코드·시세 0원 (AGPL-3.0 · API 키 0개 · 브로커 계정 0개)
모델 에이전트의 LLM 호출
시간 clone 5.1초 · install 28.5초 · 패키지 빌드 4.5초

이런 분에게 맞습니다 — Claude Code 나 Codex 를 이미 쓰고 계시고, 그 에이전트에게 시장 자료와 거래 계좌를 한자리에 쥐여 주고 싶은 분. 안 맞는 분은 체결 비용과 유동성에 민감한 전략을 이 도구의 시뮬레이터로 검증하시려는 분, 그리고 사람이 자리를 비운 채 무인 반복을 돌리시려는 분입니다.


7. 다음 편 예고

17편은 HKUDS/Vibe-Trading(★33.7k)입니다. 이 연재에서 다루는 것 중 가장 크고 weltiq 와 가장 많이 겹칩니다. OpenAlice 는 실행층을 열어 두고 브로커를 갈아 끼우게 했지만, Vibe-Trading 은 18개 브로커 커넥터와 페이퍼 주문을 자기가 전부 구현했고 외부 플러그인 커넥터는 읽기 전용으로 제한합니다. 그래서 다음 편은 "어떻게 붙이나"가 아니라 "무엇이 같고 어디서 갈라지나" 로 씁니다. weltiq 가 지는 칸도 그대로 적습니다.

weltiq 준비 — 3줄 1. 가입: {{CTA_URL}} 2. 마이 → 연결 관리에서 API 키 발급 3. claude mcp add weltiq --header "Authorization: Bearer <키>" https://weltiq.ai/mcp

OpenAlice 의 시뮬레이터가 안 재 주는 수수료·스프레드·복구를 같은 판단으로 재 보실 자리입니다.


이 글의 모든 명령·출력·숫자는 2026-09-22 에 실제로 돌려서 얻었습니다. 실제 돈이 오간 주문은 없고 전부 모의입니다. 어떤 매매 의견도 아닙니다. 여기 적지 않은 시행착오·원문 로그·돌리지 않은 항목은 검증 기록에 있습니다.