미국주식 주간거래 API 자동매매 — TTTS6036U와 BAQ
POST /uapi/overseas-stock/v1/trading/daytime-order,
tr_id는 매수 TTTS6036U · 매도 TTTS6037U입니다.
정규장 주문 경로와 엔드포인트 자체가 다르고, ORD_DVSN은 00 지정가만 됩니다.
시세도 EXCD를 NAS가 아니라 BAQ(나스닥 주간)로 바꿔야 값이 움직입니다.
정정·취소는 또 별도로 daytime-order-rvsecncl · TTTS6038U입니다.
미국주식 자동매매를 만들다 보면 같은 벽에 부딪힙니다. 미국 정규장은 한국 시간으로 밤 10시 반(서머타임 적용 시)에 열립니다. 봇은 잘 돌아도, 문제가 생겼을 때 사람이 새벽 3시에 개입할 수 없습니다.
주간거래는 그 시간표를 낮으로 당깁니다.
한국투자증권 공식 저장소의 실시간 시세 예제 설명은 미국주간거래를 10:00~16:00으로 적고 있습니다.
문제는 정규장 봇의 거래소 코드만 바꿔서는 절대 안 된다는 것입니다.
주문 경로도, tr_id도, 시세 코드도, 심지어 쓸 수 있는 주문 유형까지 따로 놉니다.
이 글은 그 갈리는 지점만 모았습니다.
목차
- 정규장과 갈리는 네 층
- 주문 — daytime-order와 TTTS6036U
- 지정가만 된다 — 시장가 분기를 지워야 하는 이유
- 정정·취소 — TTTS6038U 하나로 둘 다
- 시세 — EXCD를 BAQ로, 웹소켓 tr_key는 R로
- 정규장 봇에 주간 모드를 얹는 구조
- 자주 막히는 자리 4곳
1. 정규장과 갈리는 네 층
먼저 바뀌는 것과 안 바뀌는 것을 갈라 놓는 게 빠릅니다.
| 층 | 정규장 | 주간거래 |
|---|---|---|
| 주문 경로 | /uapi/overseas-stock/v1/trading/order | /uapi/overseas-stock/v1/trading/daytime-order |
| 주문 tr_id | 시장별로 갈림 | TTTS6036U 매수 / TTTS6037U 매도 |
| 정정·취소 | order-rvsecncl | daytime-order-rvsecncl · TTTS6038U |
| 주문 유형 | 지정가·시장가 등 | 00 지정가만 |
| 시세 EXCD | NAS / NYS / AMS | BAQ / BAY / BAA |
| 웹소켓 tr_key | DNASAAPL 형태 | R + BAQ + 티커 |
| 그대로 쓰는 것 | CANO·ACNT_PRDT_CD·PDNO·인증 헤더·OVRS_EXCG_CD(NASD/NYSE/AMEX) | |
주문 파라미터의 거래소 코드는 안 바뀌는데 시세 파라미터는 바뀝니다.
주문 쪽 OVRS_EXCG_CD는 주간거래에서도 NASD·NYSE·AMEX 네 글자를 그대로 쓰고,
시세 쪽 EXCD만 BAQ·BAY·BAA로 갈아탑니다.
이걸 반대로 하면 주문은 나가는데 가격이 전일 종가에서 멈춘 상태로 봇이 돕니다.
거래소 코드 두 축의 차이는 KIS 해외주식 현재가 API — EXCD 14개와 소수점 함정에 정리해 두었습니다.
2. 주문 — daytime-order와 TTTS6036U
공식 예제 기준 파라미터는 열한 개입니다. 정규장 주문과 이름은 거의 같지만 경로와 tr_id가 다릅니다.
| 파라미터 | 값 |
|---|---|
CANO | 계좌번호 8-2 체계의 앞 8자리 |
ACNT_PRDT_CD | 뒤 2자리 (보통 01) |
OVRS_EXCG_CD | NASD 나스닥 / NYSE 뉴욕 / AMEX 아멕스 |
PDNO | 종목코드 (티커, 예: AAPL) |
ORD_QTY | 주문수량 — 거래소별 최소 수량·단위 확인 필요 |
OVRS_ORD_UNPR | 1주당 가격, 소수점 포함 |
ORD_DVSN | 00 지정가 — 주간거래는 지정가만 |
ORD_SVR_DVSN_CD | "0" 고정 |
CTAC_TLNO / MGCO_APTM_ODNO | 연락전화번호 / 운용사지정주문번호 — 공란 가능 |
import requests
from decimal import Decimal, ROUND_HALF_UP
BASE = "https://openapi.koreainvestment.com:9443"
HEAD = {
"content-type": "application/json; charset=utf-8",
"authorization": f"Bearer {ACCESS_TOKEN}",
"appkey": APP_KEY,
"appsecret": APP_SECRET,
"custtype": "P",
}
DAYTIME_TR = {"buy": "TTTS6036U", "sell": "TTTS6037U"}
def daytime_order(side, ticker, qty, price, excg="NASD"):
"""미국 주간거래 주문 — 지정가만 가능"""
body = {
"CANO": CANO,
"ACNT_PRDT_CD": ACNT_PRDT_CD,
"OVRS_EXCG_CD": excg, # 주문은 NASD/NYSE/AMEX 그대로
"PDNO": ticker,
"ORD_QTY": str(qty),
"OVRS_ORD_UNPR": f"{price}", # 시장가 없음 -> 반드시 실제 단가
"CTAC_TLNO": "",
"MGCO_APTM_ODNO": "",
"ORD_SVR_DVSN_CD": "0",
"ORD_DVSN": "00", # 00 = 지정가
}
r = requests.post(
f"{BASE}/uapi/overseas-stock/v1/trading/daytime-order",
headers={**HEAD, "tr_id": DAYTIME_TR[side], "hashkey": make_hashkey(body)},
json=body, timeout=5,
)
res = r.json()
if res.get("rt_cd") != "0":
raise RuntimeError(f'{res.get("msg_cd")} {res.get("msg1")}')
return res["output"]["ODNO"] # 주문번호 — 정정·취소에 쓴다
주문 계열은 hashkey 헤더를 요구합니다. 이 부분은 정규장·주간거래가 같습니다.
해시키를 왜 붙여야 하고 안 붙이면 뭐가 나오는지는
KIS API hashkey — 주문에 왜 필요한가에 따로 정리했습니다.
3. 지정가만 된다 — 시장가 분기를 지워야 하는 이유
공식 예제의 ORD_DVSN 설명은 "00 : 지정가 * 주간거래는 지정가만 가능"이라고 못 박습니다.
정규장 코드에서 if signal.urgent: ord_dvsn = "31" 같은 시장가 분기를 들고 오면 주간 구간에서 거절됩니다.
그래서 주간거래 봇은 스스로 가격을 만들어야 합니다. 만드는 방법은 두 단계입니다.
- 기준가 — 주간거래 시세(
EXCD="BAQ")로 현재가를 읽습니다. - 여유폭 — 매수는 위로, 매도는 아래로 슬리피지만큼 밀고 호가단위로 반올림합니다.
def limit_from_market(last: Decimal, side: str, tick: Decimal,
zdiv: int, slip_bp: int = 15) -> Decimal:
"""현재가에 슬리피지 여유를 얹고 호가단위로 맞춘 지정가."""
k = Decimal(1) + Decimal(slip_bp) / 10000 * (1 if side == "buy" else -1)
raw = last * k
px = (raw / tick).quantize(Decimal(1), ROUND_HALF_UP) * tick
return px.quantize(Decimal(1).scaleb(-zdiv))
# 예) 현재가 231.59, 호가단위 0.01, 소수점 2자리, 매수 15bp
# -> 231.94 를 OVRS_ORD_UNPR 로 넘긴다
여유폭을 안 주면 체결이 안 되고, 크게 주면 불리하게 체결됩니다. 주간거래는 정규장보다 호가가 얇을 수 있어 같은 슬리피지 설정이 정규장과 다르게 작동합니다. 실전에 넣기 전 소액으로 주문 대비 체결률과 평균 체결가 이탈을 며칠 기록해 보고 폭을 정하십시오. 이 글은 어떤 폭이 유리한지 예측하지 않습니다. 체결 품질을 재는 방법은 주문 체결과 슬리피지에 정리해 두었습니다.
4. 정정·취소 — TTTS6038U 하나로 둘 다
경로는 POST /uapi/overseas-stock/v1/trading/daytime-order-rvsecncl이고
tr_id는 TTTS6038U 하나입니다.
정정인지 취소인지는 tr_id가 아니라 RVSE_CNCL_DVSN_CD로 가릅니다.
| 파라미터 | 값 |
|---|---|
RVSE_CNCL_DVSN_CD | 01 정정 / 02 취소 |
ORGN_ODNO | 원주문번호 — 주문 응답의 ODNO |
OVRS_EXCG_CD | NASD / NYSE / AMEX |
PDNO·ORD_QTY·OVRS_ORD_UNPR | 정정 시 새 수량·새 단가 |
주문번호를 안 들고 있으면 취소를 못 합니다.
daytime_order()가 돌려주는 ODNO를 반드시 저장하십시오.
봇이 재시작돼도 살아 있도록 메모리가 아니라 파일이나 DB에 남기는 게 안전합니다.
기록 설계는 자동매매 로깅과 매매일지를 참고하십시오.
5. 시세 — EXCD를 BAQ로, 웹소켓 tr_key는 R로
주문만 주간용으로 바꾸고 시세를 정규장 코드로 두면, 봇은 어제 종가를 보고 오늘 주문을 냅니다.
현재가 조회 tr_id는 HHDFS00000300 그대로 쓰되 EXCD만 바꿉니다.
| 시장 | 정규장 EXCD | 주간거래 EXCD | 주문 OVRS_EXCG_CD |
|---|---|---|---|
| 나스닥 | NAS | BAQ | NASD |
| 뉴욕 | NYS | BAY | NYSE |
| 아멕스 | AMS | BAA | AMEX |
체결가를 계속 받아야 하면 웹소켓 실시간지연체결가 tr_id = HDFSCNT0를 씁니다.
공식 예제 설명은 정규장 예시로 tr_key="DNASAAPL"을 들고,
미국주간거래 실시간 조회 시에는 맨 앞자리를 R로 두고 시장 구분에
BAQ(나스닥)·BAY(뉴욕)·BAA(아멕스)를 넣으라고 안내합니다.
즉 애플 주간거래는 tr_key="RBAQAAPL" 형태가 됩니다.
접속키 발급과 구독 프레임 구조 자체는
KIS 웹소켓 실시간 시세 연결과 같습니다.
6. 정규장 봇에 주간 모드를 얹는 구조
if 문을 코드 곳곳에 흩뿌리면 반드시 한 군데를 빠뜨립니다. 세션 정보를 객체 하나로 묶고, 시각에 따라 그 객체만 갈아 끼우는 편이 안전합니다.
from dataclasses import dataclass
@dataclass(frozen=True)
class Session:
name: str
order_path: str
tr_buy: str
tr_sell: str
rvsecncl_path: str
tr_rvsecncl: str
excd: dict # 시세 조회용
ws_prefix: str # 웹소켓 tr_key 접두
market_order_ok: bool
DAYTIME = Session(
"daytime",
"/uapi/overseas-stock/v1/trading/daytime-order",
"TTTS6036U", "TTTS6037U",
"/uapi/overseas-stock/v1/trading/daytime-order-rvsecncl", "TTTS6038U",
{"NASD": "BAQ", "NYSE": "BAY", "AMEX": "BAA"},
"R", False,
)
def pick_session(now_kst) -> Session | None:
if DAYTIME_OPEN <= now_kst.time() < DAYTIME_CLOSE:
return DAYTIME
if REGULAR_OPEN <= now_kst.time() or now_kst.time() < REGULAR_CLOSE:
return REGULAR
return None # 어느 세션도 아니면 주문하지 않는다
이렇게 두면 전략 코드는 session.tr_buy만 참조하면 되고,
나중에 다른 증권사를 붙일 때도 Session 하나를 더 만들면 끝납니다.
DAYTIME_OPEN·DAYTIME_CLOSE는 코드에 박지 말고 설정 파일로 빼 두십시오.
운영 시간은 증권사 공지로 바뀝니다.
7. 자주 막히는 자리 4곳
① 세션 경계에서 주문이 겹친다
주간 마감 직전에 낸 지정가가 미체결로 남아 있는데 정규장이 열리면, 봇이 같은 종목에 또 주문을 낼 수 있습니다. 세션이 바뀌는 시점에 미체결 정리(취소)를 먼저 하고 다음 세션을 시작하는 순서를 강제하십시오.
② 잔고를 내부 장부로만 계산한다
주간과 정규장을 오가면 수량이 어긋나기 쉽습니다. 주문 직후가 아니라 체결 확인 후 잔고를 API로 재조회하는 순서를 지키십시오.
③ 호출 한도는 세션과 무관하다
주간거래라고 별도 한도가 열리지 않습니다. 시세를 초 단위로 돌리면 EGW00201이 그대로 돌아옵니다.
감시는 웹소켓, 확인은 REST로 나누는 원칙은 여기서도 같습니다 —
EGW00201 초당 호출 제한 해결.
④ 이용 조건은 증권사가 정한다
주간거래 이용에 별도 신청이나 조건이 붙을 수 있고, 취급 종목 범위도 정규장과 다를 수 있습니다. 스펙 문서에 없는 부분은 증권사 공지와 고객센터로 확인하시고, 봇에는 "지원하지 않는 종목이면 주문하지 않는다"는 방어 조건을 넣어 두십시오.
자주 묻는 질문
정규장 봇의 tr_id만 바꾸면 되나요?
안 됩니다. 경로가 다릅니다. order에 TTTS6036U를 보내는 조합은 성립하지 않습니다.
경로·tr_id·주문 유형·시세 코드 네 가지를 함께 바꿔야 합니다.
모의투자에서 주간거래를 테스트할 수 있나요?
해외주식은 모의투자에서 지원하지 않는 TR이 국내보다 많습니다. 실전 소액으로 1주씩 검증하는 편이 현실적입니다. 검증 순서는 실전 투입 전 검증 3단계를 따르시면 됩니다.
키움 REST API로도 주간거래가 되나요?
증권사마다 해외주식 지원 범위가 다르고, 같은 "미국주식 API"라도 제공하는 주문 유형과 시간대가 갈립니다. 키움 쪽 지원 범위는 키움 해외주식 API 되나 — REST 미국주식 지원 범위에서 확인 방법까지 정리해 두었습니다.
2026-08-28 시점 한국투자증권 공식 저장소(koreainvestment/open-trading-api)의
해외주식 미국주간주문 예제(daytime_order·daytime_order_rvsecncl)와
실시간지연체결가 예제(delayed_ccnl)에서 확인한 경로·tr_id·파라미터명·주석 설명을 기준으로 작성했습니다.
본문의 코드는 구조를 보여주기 위한 예시이고 그대로 실전에 쓰라는 뜻이 아닙니다.
거래 시간·취급 종목·이용 조건·호출 한도는 증권사 공지로 예고 없이 바뀝니다.
운영 전 개발자 포털의 현재 명세와 증권사 공지로 대조하십시오.
이 글은 수익이나 시장 방향을 예측하지 않습니다.
낮에 도는 미국주식 봇, 만들어 드립니다
주간·정규장 세션 자동 전환, 지정가 계산, 미체결 정리, 잔고 재조회까지 묶어서 실제로 돌아가는 자동매매 프로그램으로 만들어 드립니다. 24시간 빠른 답변 가능합니다.
무료 상담 시작하기