KIS 실현손익 잔고조회 TTTC8494R — 함정 5가지
TTTC8494R(주식잔고조회_실현손익)은 일반 잔고조회 TTTC8434R과 같은 output1·output2 구조에 rlzt_pfls(실현손익)·rlzt_erng_rt(실현수익율)·real_evlu_pfls(실평가손익)·real_evlu_pfls_erng_rt 4개가 붙은 API이고, 실전계좌 전용입니다. 엔드포인트는 GET /uapi/domestic-stock/v1/trading/inquire-balance-rlz-pl, 한국투자 HTS [0800] 국내 체결기준잔고 화면을 API로 옮긴 것입니다. 공식 저장소(koreainvestment/open-trading-api, 2026-10-05 확인)에서 모의투자 지원 칸이 비어 있고, 예제 함수에는 env_dv(실전/모의) 인자 자체가 없습니다. 조회구분 INQR_DVSN은 설명엔 "00:전체", 예제엔 "02"로 서로 다르게 적혀 있습니다. 기간 실현손익을 정산할 때는 이 값이 아니라 기간별매매손익 TTTC8715R로 맞춰야 합니다.
목차
- 세 가지 손익 API — 무엇을 언제 쓰나
- 요청 파라미터 12개
- 응답 — TTTC8434R과 무엇이 다른가
- 함정 5가지
- 동작하는 코드 — 연속조회 포함
- 자주 묻는 질문
1. 세 가지 손익 API — 무엇을 언제 쓰나
봇 대시보드에 "오늘 얼마 벌었나"를 띄우려고 KIS Developers 문서를 뒤지면 손익이 붙은 API가 여럿 나옵니다. 용도가 다릅니다.
| API | tr_id | 답하는 질문 | 모의투자 |
|---|---|---|---|
| 주식잔고조회 | TTTC8434R | 지금 무엇을 몇 주, 평가손익 얼마 | ⭕ (VTTC8434R) |
| 주식잔고조회_실현손익 | TTTC8494R | 잔고 + 체결기준 실현손익을 한 번에 | 공란(미제공) |
| 기간별매매손익현황조회 | TTTC8715R | 기간 동안 종목별 확정 손익·수수료·세금 | 공란 |
| 기간별손익일별합산조회 | TTTC8708R | 기간 동안 일별 손익 합계 | 공란 |
모의투자 칸은 공식 저장소 legacy/README.md의 지원 표 기준입니다(legacy/postman/README.md에서는 실전 칸만 ⭕). TTTC8494R의 자리는 "잔고를 이미 매번 조회하는 봇이, 호출 하나로 실현손익까지 같이 받고 싶을 때"입니다. 정산·세금 계산용은 아닙니다(함정 ⑤).
2. 요청 파라미터 12개
공식 Postman 컬렉션 실전계좌_POSTMAN_샘플코드_v2.6.json의 요청 URL 원문입니다.
{{PROD}}/uapi/domestic-stock/v1/trading/inquire-balance-rlz-pl?CANO={{CANO_REAL}}&ACNT_PRDT_CD=01&AFHR_FLPR_YN=N&OFL_YN=&INQR_DVSN=02&UNPR_DVSN=01&FUND_STTL_ICLD_YN=N&FNCG_AMT_AUTO_RDPT_YN=N&PRCS_DVSN=01&COST_ICLD_YN=N&CTX_AREA_FK100=&CTX_AREA_NK100=
| 파라미터 | 설명(공식) | 예제 값 |
|---|---|---|
CANO | 종합계좌번호, 8-2 체계의 앞 8자리 | 계좌번호 |
ACNT_PRDT_CD | 계좌상품코드, 뒤 2자리 | 01 |
AFHR_FLPR_YN | 시간외단일가여부 N:기본값 / Y:시간외단일가 | N |
OFL_YN | 오프라인여부(공란) | 빈 값 |
INQR_DVSN | 조회구분(00 : 전체) | 02 ← 불일치 |
UNPR_DVSN | 단가구분(01 : 기본값) | 01 |
FUND_STTL_ICLD_YN | 펀드결제포함여부 N/Y | N |
FNCG_AMT_AUTO_RDPT_YN | 융자금액자동상환여부 N:기본값 | N |
PRCS_DVSN | 00:전일매매포함 / 01:전일매매미포함 | 01 |
COST_ICLD_YN | 비용포함여부 N:포함하지 않음 / Y:포함 | N |
CTX_AREA_FK100 | 연속조회검색조건100, 최초 공란 | 빈 값 |
CTX_AREA_NK100 | 연속조회키100, 최초 공란 | 빈 값 |
헤더는 다른 KIS 조회와 같습니다 — authorization(Bearer access_token), appkey, appsecret, tr_id=TTTC8494R, custtype=P. 토큰 발급은 KIS API 키 발급 30분 가이드를 보세요.
3. 응답 — TTTC8434R과 무엇이 다른가
두 API의 공식 예제 chk_*.py에 있는 COLUMN_MAPPING을 집합으로 비교하면 차이는 7개뿐입니다. 나머지(pdno, prdt_name, hldg_qty, ord_psbl_qty, pchs_avg_pric, evlu_pfls_amt, dnca_tot_amt, tot_evlu_amt, nass_amt 등)는 같습니다.
| 구분 | 필드 | 공식 한글명 |
|---|---|---|
| TTTC8494R에만 | rlzt_pfls | 실현손익 |
rlzt_erng_rt | 실현수익율 | |
real_evlu_pfls | 실평가손익 | |
real_evlu_pfls_erng_rt | 실평가손익수익율 | |
| TTTC8434R에만 | item_mgna_rt_name | 종목증거금율명 |
grta_rt_name | 보증금율명 | |
sbst_pric | 대용가격 |
즉 증거금율·대용가격이 필요한 신용·담보 로직이면 TTTC8434R을 그대로 써야 하고, 손익 표시가 목적이면 TTTC8494R 하나로 충분합니다.
4. 함정 5가지
함정 ① 모의투자에서 개발하다 막힌다
공식 예제의 함수 시그니처부터 다릅니다.
# examples_llm/domestic_stock/inquire_balance/inquire_balance.py (TTTC8434R)
def inquire_balance(env_dv: str, cano: str, acnt_prdt_cd: str, ...)
if env_dv == "real": tr_id = "TTTC8434R"
elif env_dv == "demo": tr_id = "VTTC8434R"
# examples_llm/domestic_stock/inquire_balance_rlz_pl/inquire_balance_rlz_pl.py (TTTC8494R)
def inquire_balance_rlz_pl(cano: str, acnt_prdt_cd: str, ...) # env_dv 인자 자체가 없음
tr_id = "TTTC8494R" # 주식잔고조회_실현손익
문제는 인증 모듈입니다. 공식 kis_auth.py의 _url_fetch()는 모의 모드에서 tr_id 첫 글자를 자동으로 바꿉니다.
tr_id = ptr_id
if ptr_id[0] in ("T", "J", "C"): # 실전투자용 TR id 체크
if isPaperTrading(): # 모의투자용 TR id 식별
tr_id = "V" + ptr_id[1:]
모의 모드로 이 예제를 돌리면 요청 헤더에는 VTTC8494R이 들어가는데, 모의 서버 제공 목록에 이 API가 없습니다. 에러 문구를 보고 파라미터를 의심하기 쉽지만 원인은 환경입니다. 모의에서 개발한 봇을 실전으로 옮길 때 생기는 다른 차이는 모의→실전 전환 체크리스트에 모았습니다. 대응: 모의 단계에선 TTTC8434R로 잔고를 받고 실현손익 표시는 끄거나, 실전 소액 계좌에서만 이 API를 켭니다.
함정 ② INQR_DVSN — 문서는 00, 예제는 02
# 같은 저장소, 같은 API, 세 가지 값
docstring : inqr_dvsn (str): [필수] 조회구분 (00:전체)
chk 예제 : inqr_dvsn="02"
Postman : "INQR_DVSN" value "02" / description "조회구분(00 : 전체)"
legacy : "INQR_DVSN": "00", # 00 : 전체
일반 잔고 TTTC8434R은 INQR_DVSN이 01(대출일별) / 02(종목별)입니다. TTTC8494R 설명은 "00:전체" 하나만 적어 두고, 최신 예제와 Postman은 02를 보냅니다. 어느 쪽이 맞는지 공식 설명만으로는 확정할 수 없습니다. 대응: 실계좌에서 00과 02를 한 번씩 호출해 output1 행 수와 output2 합계가 같은지 비교한 뒤 한 값으로 고정하세요. 신용 보유분이 있는 계좌라면 차이가 날 가능성이 더 큽니다.
함정 ③ PRCS_DVSN — 전일 매매를 넣느냐 빼느냐
PRCS_DVSN은 00(전일매매포함) / 01(전일매매미포함)인데 최신 예제는 01, legacy/Sample01/kis_domstk.py는 00입니다. 응답에 bfdy_buy_qty(전일매수수량)·bfdy_sll_qty·bfdy_buy_amt·bfdy_sll_amt·bfdy_tlex_amt(전일제비용금액) 같은 전일 필드가 있으므로, 전일 청산분까지 화면에 보여야 하는 봇은 00을 써야 의미가 맞습니다. 오전 장 시작 직후 대시보드가 "어제 판 종목"을 놓친다면 이 값부터 보세요.
함정 ④ output1·output2를 헷갈린다
공식 chk_inquire_balance_rlz_pl.py는 output1(종목 행)과 output2(계좌 합계) 필드를 하나의 COLUMN_MAPPING에 섞어 두었고, rlzt_pfls 등은 nass_amt·asst_icdc_amt 같은 합계 필드 뒤에 나열돼 있습니다. legacy 예제는 더 헷갈립니다 — get_inquire_balance_rlz_pl_lst()는 주석에 "Output2"라고 써 놓고 실제로는 output1을 읽고, get_inquire_balance_rlz_pl_obj()는 그 반대입니다. 대응: 첫 실행에서 output1[0].keys()와 output2[0].keys()를 찍어 실제 위치를 확인한 뒤 코드를 고정하세요. 값은 전부 문자열이라 int()/float() 변환이 필요합니다.
함정 ⑤ rlzt_pfls를 정산 숫자로 쓴다
공식 설명은 rlzt_pfls를 "실현손익"이라고만 적고, 어느 기간의 실현인지(당일·누적), COST_ICLD_YN=Y일 때 무슨 비용이 빠지는지는 적지 않습니다. HTS [0800] 화면 기준이라는 안내가 전부입니다. 수수료·제세금이 항목별로 필요한 월간 성과 보고, 세금 계산에는 fee·tl_tax를 따로 주는 TTTC8715R을 쓰세요. TTTC8494R은 "지금 화면에 띄우는 근사치"로 두고, 하루 한 번 TTTC8715R 합계와 대조하는 구조가 안전합니다.
연속조회도 확인하세요. 예제는 응답 헤더 tr_cont가 M 또는 F면 ctx_area_fk100·ctx_area_nk100을 다음 요청에 넣고 tr_cont=N으로 재호출합니다. TTTC8434R 예제에는 "실전 1회 최대 50건"이 명시돼 있지만 TTTC8494R 예제에는 건수 문구가 없습니다. 보유 종목이 많다면 연속조회를 처음부터 넣어 두세요 — 구조는 잔고조회 연속조회 글과 같습니다.
5. 동작하는 코드 — 연속조회 포함
requests만 쓰는 단독 버전입니다. 키·계좌번호는 환경변수로 받습니다(코드에 직접 쓰지 마세요).
import os, time, requests
BASE = "https://openapi.koreainvestment.com:9443" # 실전 전용 — 모의 도메인에선 쓰지 않는다
URL = BASE + "/uapi/domestic-stock/v1/trading/inquire-balance-rlz-pl"
def _headers(tr_cont=""):
return {"content-type": "application/json; charset=utf-8",
"authorization": f"Bearer {os.environ['KIS_ACCESS_TOKEN']}",
"appkey": os.environ["KIS_APPKEY"], "appsecret": os.environ["KIS_APPSECRET"],
"tr_id": "TTTC8494R", "tr_cont": tr_cont, "custtype": "P"}
def balance_rlz_pl(cano, acnt_prdt_cd="01", max_pages=10):
params = {"CANO": cano, "ACNT_PRDT_CD": acnt_prdt_cd, "AFHR_FLPR_YN": "N", "OFL_YN": "",
"INQR_DVSN": "02", "UNPR_DVSN": "01", "FUND_STTL_ICLD_YN": "N",
"FNCG_AMT_AUTO_RDPT_YN": "N", "PRCS_DVSN": "01", "COST_ICLD_YN": "N",
"CTX_AREA_FK100": "", "CTX_AREA_NK100": ""}
rows, summary, tr_cont = [], None, ""
for _ in range(max_pages):
r = requests.get(URL, headers=_headers(tr_cont), params=params, timeout=10)
body = r.json()
if body.get("rt_cd") != "0":
raise RuntimeError(f'{body.get("msg_cd")} {body.get("msg1")}')
rows += body.get("output1") or []
o2 = body.get("output2")
if o2:
summary = o2[0] if isinstance(o2, list) else o2
if r.headers.get("tr_cont") not in ("F", "M"): # 응답 "헤더"의 tr_cont
break
params["CTX_AREA_FK100"] = body["ctx_area_fk100"]
params["CTX_AREA_NK100"] = body["ctx_area_nk100"]
tr_cont = "N" # 두 번째 호출부터 N
time.sleep(0.1)
return rows, summary
rows, s = balance_rlz_pl(os.environ["KIS_CANO"])
held = [x for x in rows if int(x["hldg_qty"]) > 0] # 전부 문자열로 온다
print(sorted(s.keys())) # 첫 실행 땐 키부터 확인
print("실현손익", float(s["rlzt_pfls"]), "실평가손익", float(s["real_evlu_pfls"]))
대시보드가 몇 초마다 이 API를 부르면 주문·시세 조회와 같은 한도를 나눠 씁니다. 몰리면 아래 응답이 오니 EGW00201 해결 글처럼 호출 간격을 둡니다. 다른 에러코드는 KIS API 에러코드 정리에 있습니다.
{"rt_cd": "1", "msg_cd": "EGW00201", "msg1": "초당 거래건수를 초과하였습니다."}
키움증권 REST API를 쓰는 경우 같은 역할은 ka10072 실현손익 조회가 맡습니다. 증권사마다 "실현손익"의 기간·비용 기준이 다르니 숫자를 섞어 쓰지 마세요.
이 글의 tr_id·파라미터·필드는 한국투자증권 공식 GitHub 저장소를 2026-10-05에 내려받아 대조한 것입니다. 스펙은 예고 없이 바뀔 수 있으니 KIS Developers 공식 문서를 함께 확인하세요.
6. 자주 묻는 질문
TTTC8494R은 모의투자에서 되나요?
공식 저장소 legacy/README.md의 지원 표에서 주식잔고조회_실현손익의 모의투자 칸은 비어 있고, 공식 예제 함수에도 실전/모의를 고르는 env_dv 인자가 없습니다. 공식 kis_auth.py는 모의 모드에서 tr_id를 VTTC8494R로 바꿔 보내므로 모의 서버에서는 동작하지 않는다고 보고 개발하는 편이 안전합니다.
TTTC8434R과 TTTC8494R 중 무엇을 써야 하나요?
손익 표시가 목적이면 TTTC8494R 하나로 잔고와 실현손익을 같이 받을 수 있습니다. 다만 실전 전용이고 증거금율·대용가격 필드(item_mgna_rt_name, grta_rt_name, sbst_pric)가 없으므로, 모의 개발 단계이거나 신용·담보 로직이 있으면 TTTC8434R을 씁니다.
INQR_DVSN에는 00과 02 중 무엇을 넣나요?
공식 설명은 00:전체, 최신 예제와 Postman 요청은 02, legacy 예제는 00으로 서로 다릅니다. 실계좌에서 두 값으로 한 번씩 호출해 output1 행 수와 output2 합계가 같은지 확인한 뒤 하나로 고정하는 것을 권합니다.
rlzt_pfls 값으로 월 수익을 계산해도 되나요?
권하지 않습니다. 공식 설명에 실현손익의 기간과 비용 포함 범위가 적혀 있지 않습니다. 수수료(fee)와 제세금(tl_tax)이 따로 필요한 정산에는 기간별매매손익현황조회 TTTC8715R을 쓰고, TTTC8494R은 화면 표시용 근사치로 두는 편이 안전합니다.