설정·스크립트·스킬·문서·큐레이션 메모리 추적. 시크릿(credentials/identity)·런타임 상태(state/logs/sessions/sqlite)· 백업(clobbered/bak)·dream 캐시는 .gitignore로 제외. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
18 KiB
name, description
| name | description |
|---|---|
| order-trading | 관리자님이 명시적으로 매수/매도를 지시하거나 활성 카드의 수량/가격을 수정할 때만 사용. "삼성 5주 75000원에 사줘", "카카오 10주 시장가 매수", "ISA에서 005930 3주 팔아줘", "삼성전자 100만원어치 매수해줘" 같은 신규 매매 지시 + "수량 20주로 바꿔줘", "가격 76000원으로", "예산 200만원으로" 같은 카드 수정 지시. 0 입력("0주로", "취소") → 카드 취소. **키움에 이미 접수된 미체결 주문**의 정정/취소("미체결 취소해줘", "ord_no 123 가격 76000으로 정정")도 이 스킬에서 처리. 워치리스트 도달이나 시장 이벤트, 자체 추론으로는 절대 트리거하지 않음. PIN 답장(4~8자리)이나 매매 제어(/orders_off 등)는 order-controls 스킬을 사용. |
order-trading
관리자님 매매 지시 → 페이로드 추출 → orders.handler.propose_and_send 호출 → 카드+PIN 분리 발송. 결정권은 PIN echo 에 있다.
절대 원칙
- 자율 매매 금지 — 워치리스트 도달·뉴스·시장 이벤트로는 절대 트리거 X. 관리자님 명시적 지시("사줘"/"팔아줘"/"매수"/"매도")가 있을 때만.
- 추측·할루시네이션 금지 — 종목명·수량·가격·계좌가 모호하면 카드 발행하지 말고 되묻는다.
- 사이드카 ON 상태면 시도 X —
state/orders_disabled존재 시 거부 메시지가 반환됨. 그 메시지 그대로 관리자님께 전달. - 카드 발행 후 확인문은 한 줄만 —
--send가 카드+PIN을 텔레그램에 직접 보내므로 장황한 안내(PIN 회신 대기,120초 만료등)는 보내지 않는다. 성공 시 레이는[계좌명] [종목명] [매수/매도] 카드 발급완료형식의 짧은 한국어 한 줄만 보낸다. 예:가희 일반 LG전자 매수 카드 발급완료. 단, 거부·오류·모호해서 되묻는 경우는 그대로 안내한다.
페이로드 추출 규칙
자연어에서 다음을 식별:
- account — "본인 일반"·"일반"·"ISA"·"가희 일반"·"가희_일반"·"가희 ISA"·"가희_ISA". 명시 없으면 무조건 되묻기. 자동 default 없음. "가희" 만 있고 "일반/ISA" 미명시여도 되묻기. 4계좌 모호함 방지가 default 자동 가정보다 우선.
- side — "사", "매수", "buy" →
BUY/ "팔", "매도", "sell" →SELL. - symbol — 6자리 종목코드면 그대로. 종목명("삼성", "삼성전자", "카카오")이면
kiwoom_client.resolve_stock_codeCLI 로 코드 변환. - symbol_name — 한글 종목명. resolve 결과 또는 사용자 입력.
- qty — 숫자(주). "5주"·"5". budget 과 동시 지정 불가.
- budget — 원 단위 금액. "100만원어치"·"50만원"·"1,000,000원어치"·"30만원으로". qty 대신 입력. 매수/매도 둘 다 가능.
- 환산: 키움 호가창 기준 1주 가격으로 floor 나눗셈. 매수 = 매도1호가, 매도 = 매수1호가.
- BUY +1 정책: 1주 가격(매도1호가) ≤ 300,000원 이고 floor 잔액이 0보다 크면 1주 더 매수. 예산을 살짝 초과해서 14주처럼. 30만원 초과 고가주는 floor 유지. SELL 은 항상 floor (보유수량 초과 매도 방지).
- 정수 주식만. 카드에는 잔액(또는 bumped 시 초과액)·매수가능금액(BUY)·보유수량(SELL) 표시.
- 예산이 1주 가격보다 작으면
BUDGET_TOO_SMALL거부. - 키움에는 무조건 시장가(
trde_tp=3)로 발주. 환산 가격은 우리 내부 계산용일 뿐 키움에 안 감. - 자연어 단위 정리: "100만원" → 1000000, "50만" → 500000, "1.5억" → 150000000. 천단위 콤마 제거.
- "전액매수" / "예수금 다 써서" / "예수금 전부로" / "전부 매수" →
kiwoom_client.get_balance(account_label)결과의ord_alow_amt(주문가능금액) 를--budget으로 사용.ord_alow_amt가 0/누락이면d2_entra폴백.entr은 절대 사용 X (미정산 매도대금 포함되어 부풀려진 값).d2_entra를 빼는 계산(entr - d2_entra등) 절대 금지 — D+2는 "이틀 후 도착"이 아니라 "결제 사이클 끝났을 때의 진짜 잔액"이며 그 자체가 가용 (auto-memoryreference_kiwoom_deposit_basis.md참조).
- order_type — 가격 명시되면
LIMIT. "시장가" 명시 →MARKET. "지금 바로", "즉시", "빨리", "당장" 명시 →AGGRESSIVE_LIMIT. budget 입력은 자동MARKET(예산 기반은 시장가만 지원). 그 외 가격 미명시면 되묻기. - price —
LIMIT일 때만. 천단위 콤마/원 표기 정리("75,000원" → 75000). - routing_force — 보통 명시 X. 사용자가 "넥스트레이드로", "NXT로" →
NX. "정규장으로", "KRX로" →KRX. 명시 없으면 SOR 자동.
추출 결과를 dict 로 정리한 후 CLI 한 번 호출.
진입점 (CLI)
cd ~/.openclaw/agents/stock/workspace/scripts
# 수량 입력
python3 -m orders.handler propose <account> <side> <symbol> <symbol_name> <qty> <order_type> [price] [routing] --send
# 예산 입력 (qty 자리 '-' + --budget <원>)
python3 -m orders.handler propose <account> <side> <symbol> <symbol_name> - MARKET --budget <won> [routing] --send
# 활성 카드 수정 — qty/price/order_type/budget/routing 중 하나 이상
python3 -m orders.handler amend [--qty N] [--price W] [--order-type LIMIT|MARKET|AGGRESSIVE_LIMIT] [--budget W] [--routing AL|NX|KRX] --send
# 활성 카드 취소
python3 -m orders.handler cancel --send
# 키움에 접수된 미체결 주문 조회
python3 -m orders.handler open-orders [--account A]
# 키움에 접수된 미체결 주문 취소 (PIN 없음, 안전 방향)
python3 -m orders.handler cancel-order [--ord-no N] [--account A] --live --send
# 키움에 접수된 미체결 주문 정정 (PIN 없음)
python3 -m orders.handler modify-order [--ord-no N] [--account A] [--qty Q] [--price P] --live --send
--send 플래그가 카드 + PIN 두 메시지를 텔레그램으로 자동 분리 발송한다. skill 응답은 발행 결과 요약만.
--live: 미체결 정정/취소(cancel-order/modify-order)는 안전을 위해 기본 dry-run. 실주문은 --live 명시 필요.
예시
예 1 — 본인 일반 매수 지정가
- 입력: "삼성 5주 75000원에 사줘"
- 명령:
python3 -m orders.handler propose 일반 BUY 005930 삼성전자 5 LIMIT 75000 --send - 응답:
[계좌명] [종목명] [매수/매도] 카드 발급완료
예 2 — 가희 ISA 매도 시장가 (NXT 시간대 외)
- 입력: "가희 ISA에서 카카오 10주 시장가로 팔아줘"
- 명령:
python3 -m orders.handler propose 가희_ISA SELL 035720 카카오 10 MARKET --send - 응답:
[계좌명] [종목명] [매수/매도] 카드 발급완료
예 3 — 공격적 지정가
- 입력: "삼성 3주 지금 바로 사줘"
- 명령:
python3 -m orders.handler propose 일반 BUY 005930 삼성전자 3 AGGRESSIVE_LIMIT --send - 응답:
[계좌명] [종목명] [매수/매도] 카드 발급완료
예 3-2 — 예산 기반 시장가 매수
- 입력: "삼성전자 100만원어치 매수해줘" (계좌는 직전 컨텍스트 또는 되묻기로 확정 가정)
- 명령 (일반 계좌일 때):
python3 -m orders.handler propose 일반 BUY 005930 삼성전자 - MARKET --budget 1000000 --send - 응답:
[계좌명] [종목명] [매수/매도] 카드 발급완료카드 자체에 예산 환산 정보가 표시됨.
예 3-3 — 예산이 1주 가격보다 작음
- 입력: "LG전자 5만원어치 사줘" (1주 ≈ 85,000원)
- 명령:
python3 -m orders.handler propose 일반 BUY 066570 LG전자 - MARKET --budget 50000 --send - 응답 (카드 발행 X, 거부): "⛔ 거부 [BUDGET_TOO_SMALL]: 1주 가격(85,000원, 매도1호가)이 예산(50,000원)보다 큽니다"
예 3-4 — 예산 기반 매도
- 입력: "ISA에서 카카오 50만원어치 팔아줘"
- 명령:
python3 -m orders.handler propose ISA SELL 035720 카카오 - MARKET --budget 500000 --send - 응답:
[계좌명] [종목명] [매수/매도] 카드 발급완료카드 자체에 예산 환산 정보가 표시됨.
예 4 — 계좌 미명시 → 넘버링 되묻기
- 입력: "삼성전자 1주 시장가로 사줘"
- 응답 (카드 발행 X):
어느 계좌에서 매수할까요? 1) 일반 2) ISA 3) 가희_일반 4) 가희_ISA - 사용자가 숫자(
1~4) 또는 라벨(일반/ISA/가희_일반/가희_ISA) 회신 시 직전 매매 의도와 합쳐 propose CLI 호출.
예 5 — "가희" 만 있고 일반/ISA 미명시 → 넘버링 되묻기
- 입력: "가희로 카카오 10주 사줘"
- 응답 (카드 발행 X):
가희 어느 계좌인가요? 1) 가희_일반 2) 가희_ISA - 숫자(
1~2) 또는 라벨 회신 시 propose 호출.
예 6 — 모호한 수량/가격은 되묻기
- 입력: "삼성 좀 사줘"
- 응답: "어느 계좌, 몇 주(또는 얼마어치), 가격(또는 시장가)을 알려주세요. 예:
일반에서 삼성 5주 75000원에 매수또는일반에서 삼성 100만원어치 매수."
카드 수정 / 취소 (활성 카드 있을 때)
활성 카드(미만료·미소비)가 있을 때 관리자님이 일부 항목만 바꾸길 원하면 amend 호출.
- 수정 가능 필드:
qty,price,order_type,budget,routing_force,symbol(+symbol_name),account. 한 번에 여러 개 가능. - 수정 불가:
side(매수↔매도) — 의미가 정반대라 새 카드로 발행. "방향 바꿔" 류 입력은 "방향(매수/매도)은 amend 불가합니다. /orders_cancel 후 새로 발행해 주세요." 안내. - 종목 변경 시 symbol_name 동반 필수: 자연어 종목명 →
kiwoom_client.resolve_stock_code로 6자리 코드 변환 후 코드+이름 둘 다 명시. - 계좌 변경 시 PIN 길이 자동 재조정: 본인↔가희 전환 시 새 PIN 은 본인 4자리/가희 8자리로 발급.
- PIN 전체 재발급: amend 성공 시 새 PIN 다시 발송 + 만료 120초 리셋. card_id 는 유지.
- 0 입력 = 취소:
qty/price/budget중 하나라도 0 이면 cancel 위임. 0 + 다른 amend 값 동시 입력은AMBIGUOUS_AMEND거부. - 가드 재실행: 잔고·보유·가격대·시간대·NXT·상태 12개 가드 전부 재검증. 통과 시에만 갱신.
자연어 트리거 예시
| 입력 | CLI |
|---|---|
| "수량 20주로 바꿔줘" / "20주로" | amend --qty 20 --send |
| "가격 76000원으로" | amend --price 76000 --send |
| "20주 76000원으로" | amend --qty 20 --price 76000 --send |
| "시장가로 바꿔" | amend --order-type MARKET --send |
| "예산 200만원으로" | amend --budget 2000000 --send |
| "지금 바로로 바꿔" | amend --order-type AGGRESSIVE_LIMIT --send |
| "ISA로 바꿔" / "가희 일반으로" | amend --account ISA --send (계좌만) |
| "카카오로 바꿔" / "035720으로" | amend --symbol 035720 --symbol-name 카카오 --send |
| "ISA에서 카카오로" | amend --account ISA --symbol 035720 --symbol-name 카카오 --send |
| "0주로" / "취소" / "그만" | amend --qty 0 --send (또는 cancel --send) |
활성 카드가 없으면 NO_ACTIVE_CARD 거부 응답을 그대로 echo.
예 7 — 수량 수정
- 입력: "수량 20주로 바꿔줘"
- 명령:
python3 -m orders.handler amend --qty 20 --send - 응답:
[계좌명] [종목명] [매수/매도] 카드 발급완료
예 8 — 가격 + 주문방식 동시 수정
- 입력: "85000원 지정가로"
- 명령:
python3 -m orders.handler amend --order-type LIMIT --price 85000 --send
예 9 — 0 입력으로 취소
- 입력: "0주로" / "취소해줘" / "그만"
- 명령:
python3 -m orders.handler amend --qty 0 --send # 또는 python3 -m orders.handler cancel --send
예 10 — 계좌만 변경 (본인↔가희 전환 시 PIN 길이 자동)
- 입력: "가희 ISA로 바꿔" (활성 카드 본인 일반)
- 명령:
python3 -m orders.handler amend --account 가희_ISA --send - 응답: PIN 8자리 영숫자로 재발급된 카드 발행.
예 11 — 종목 변경 (코드+이름 동반 필수)
- 입력: "카카오로 바꿔서 매수" (활성 카드 005930 삼성전자)
- 처리:
kiwoom_client.resolve_stock_code 카카오→035720 - 명령:
python3 -m orders.handler amend --symbol 035720 --symbol-name 카카오 --send
예 12 — 종목·계좌 동시 변경
- 입력: "ISA에서 카카오 10주로 바꿔"
- 명령:
python3 -m orders.handler amend --account ISA --symbol 035720 --symbol-name 카카오 --qty 10 --send
예 13 — 방향 변경 시도 → 거부 안내
- 입력: "매도로 바꿔" (활성 카드는 BUY)
- 응답: "방향(매수/매도)은 amend 불가합니다.
/orders_cancel후 새로 발행해 주세요."
되묻기 응답 처리 규칙
직전 턴에서 레이가 넘버링 옵션을 제시하고, 사용자가 짧은 숫자/라벨로만 회신한 경우:
- 1자리 숫자 (
1~4) — 계좌 선택. 직전 매매 의도(종목·수량·가격·side)와 합쳐 propose 호출. - 라벨 직접 입력(
일반,ISA,가희_일반,가희_ISA) — 동일하게 처리. - PIN 과 혼동 주의 — PIN 은 본인 4자리 / 가희 8자리. 1
2자리 숫자는 PIN 이 아니다. 활성 카드가 있더라도 12자리 숫자는 계좌 선택으로 해석. - 직전 턴이 매매 되묻기가 아니면 숫자만 회신은 무시하고 일반 응답.
예 5 — 사이드카 ON
- 입력: "삼성 5주 75000원에 사줘"
- 명령 결과:
{"ok": false, "message": "🚫 매매 비활성화 상태..."} - 응답: 그대로 echo. "🚫 매매 비활성화 상태입니다. /orders_on 으로 재개하세요."
거부되는 요청 (이 스킬 호출하지 말 것)
- "워치리스트 도달했으니 자동 매수해" → 자율 매매 금지. 카드 발행 X.
- "내일 자동으로 사줘" → 예약 매매 X. 시점에 관리자님이 직접 명령.
- "이거 살까 말까?" → 의견 질문이지 매매 지시 아님. 카드 발행 X.
가드 (자동 적용 — 이 스킬 호출 후 거부 메시지가 오면 그대로 echo)
orders.handler.propose_trade 가 다음을 자동 검증:
- 계좌 화이트리스트
- 거래시간 + NXT 매트릭스 (NXT 시간대에 NXT 미지원 종목 → 거부)
- NXT 시간대·KRX 단일가 시장가 → 거부
- ±30% 상한가/하한가
- 거래정지·VI·휴장일
- 잔고/보유수량 사전조회
- 거래 간 60초 / 같은 종목 3분 딜레이 (실주문 접수 이후만 카운트 — PIN 오타·취소·키움 거절은 면제)
- 같은 종목 3분 — 키움 진실 소스(kt00007) 추가 검증. 우리 ledger 모르는 매매(NETWORK 사각·사용자 키움앱 매매)도 차단. 키움 조회 실패 시 보수적 차단
- 사이드카 ON / LLM 환경변수 차단
- 예산 환산 (budget 입력 시 qty 결정 직전):
BUDGET_INVALID(0/음수),NO_ORDERBOOK(호가창 조회 실패),BUDGET_TOO_SMALL(1주 가격 > 예산)
거부 시 ⛔ 거부 [코드]: 메시지 형태. 그대로 관리자님께 전달.
키움 접수 후 미체결 주문 정정·취소 (kt10002 / kt10003)
amend / cancel 은 활성 카드(PIN 미입력 단계) 만 처리한다. PIN 통과 후 키움에 접수된 미체결 주문은 별도 진입점이 처리한다 — cancel-order / modify-order.
절대 원칙
- PIN 게이트 없음 — 취소는 안전 방향이라 즉시 실행. 정정도 동일 정책 (관리자님 결정).
- 자율 트리거 금지 — 워치리스트·시장 이벤트로 자동 취소/정정 발화 X.
--live없으면 dry-run — 안전 기본값. 실주문은--live명시 필요.- 시장가 미체결 정정 불가 — 키움 명세상 가격 0 불가. 취소 후 신규 발주로 안내.
자연어 트리거
| 입력 | CLI |
|---|---|
| "미체결 보여줘" / "취소할 주문 뭐 있어" | open-orders --send (혹은 결과를 텍스트로 echo) |
| "미체결 취소" (1건만 있을 때) | cancel-order --live --send |
| "ord_no 12345 취소" | cancel-order --ord-no 12345 --live --send |
| "ISA 미체결 다 취소" (ISA에 1건) | cancel-order --account ISA --live --send |
| "ord_no 12345 가격 76000으로 정정" | modify-order --ord-no 12345 --price 76000 --live --send |
| "ord_no 12345 수량 3주로 정정" | modify-order --ord-no 12345 --qty 3 --live --send |
자동 대상 추출
ord_no명시 — 그대로 사용. account 도 같이 주면 빠르고, 안 줘도 4계좌에서 매칭.ord_no미명시 + 미체결 1건 — 자동 선택.ord_no미명시 + 미체결 2건 이상 —AMBIGUOUS거부 + 리스트 echo. 관리자님께 ord_no 선택 요청.- 미체결 0건 —
NO_OPEN_ORDERS거부.
응답 형식
- 취소 성공:
✅ 취소 접수 · 원주문 ord_no=X → 취소 ord_no=Y · [계좌] 종목 매수/매도 N주 (KRX)- 이후 broker 확정 시 후속 알림:
✅ 매수/매도 취소 확인: 종목 N주 취소됨\n원주문: X / 취소주문: Y(fill_watcher 데몬이 ka10075 폴링) - 30분 미확인 시:
⏱️ 매수/매도 취소 30분째 미확인 ...
- 이후 broker 확정 시 후속 알림:
- 정정 성공:
✏️ 정정 접수 · 원주문 ord_no=X → 정정 ord_no=Y · [계좌] 종목 매수/매도 5주 @ 75,000원 → 3주 @ 76,000원 (KRX) - dry-run:
🧪 [DRY-RUN] ... - 키움 거절:
⛔ 취소/정정 실패 [BROKER_REJECT] · ord_no=X ...\n사유: ...
예시
예 A — 미체결 1건 즉시 취소
- 입력: "미체결 취소해줘"
- 명령:
python3 -m orders.handler cancel-order --live --send - 응답:
✅ 취소 접수 ...(단일 한 줄)
예 B — ord_no 명시 정정 (가격만)
- 입력: "0001234 가격 76000으로 정정"
- 명령:
python3 -m orders.handler modify-order --ord-no 0001234 --price 76000 --live --send
예 C — 다수 미체결 → 모호
- 입력: "미체결 취소"
- 명령:
python3 -m orders.handler cancel-order --live --send - 응답:
대상 ord_no 를 명시해 주세요: ord_no=0001234 · [일반] 삼성전자 (005930) 매수 5주 @ 75,000원 · 미체결 5주 ... ord_no=0005678 · [ISA] 카카오 (035720) 매도 10주 @ 50,000원 · 미체결 10주 ... - 관리자님이 ord_no 회신 시 그 값으로 재호출.
예 D — 시장가 정정 시도 → 거부 안내
- 입력: "시장가 미체결 가격 76000으로 정정" (원주문이 시장가)
- 응답:
⛔ 시장가 미체결은 정정 불가 (가격 0). 취소 후 신규 발주하세요.