From ede2dec97f7241b4e0b01258f712c82d3e605321 Mon Sep 17 00:00:00 2001 From: Seth Jeon Date: Tue, 4 Aug 2026 01:58:58 +0000 Subject: [PATCH 01/10] Fix auth for persoanl pension and IRP --- kis_agent/core/auth.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kis_agent/core/auth.py b/kis_agent/core/auth.py index 8b1bd72..e2277ff 100644 --- a/kis_agent/core/auth.py +++ b/kis_agent/core/auth.py @@ -363,6 +363,10 @@ def changeTREnv( svr == "prod" and product == "03" or svr == "prod" and product == "08" ): # 실전투자 선물옵션(파생) cfg["my_acct"] = _cfg.get("my_acct_future", "") + elif svr == "prod" and product == "22": # 연금계좌 + cfg["my_acct"] = _cfg.get("my_acct__stock", "") + elif svr == "prod" and product == "29": # IRP. 주문 불가. 계좌조회/시세조회만 가능 + cfg["my_acct"] = _cfg.get("my_acct__stock", "") elif svr == "vps" and product == "01": # 모의투자 주식투자, 위탁계좌, 투자계좌 cfg["my_acct"] = _cfg.get("my_paper_stock", "") elif svr == "vps" and product == "03": # 모의투자 선물옵션(파생) From 0ef026c23fa9fd9ebe256206b5d77a8ee205e5c2 Mon Sep 17 00:00:00 2001 From: Seth Jeon Date: Tue, 4 Aug 2026 01:59:25 +0000 Subject: [PATCH 02/10] Implement query IRP balance --- kis_agent/account/balance_query_api.py | 35 +++++++++++++++----------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/kis_agent/account/balance_query_api.py b/kis_agent/account/balance_query_api.py index 91d748a..d6939a6 100644 --- a/kis_agent/account/balance_query_api.py +++ b/kis_agent/account/balance_query_api.py @@ -28,22 +28,27 @@ def __init__( def get_account_balance(self) -> Optional[Dict]: """계좌 잔고 조회. output1=보유종목, output2=요약(예수금/총평가/순자산).""" + is_irp = self.account["ACNT_PRDT_CD"] == "29" + endpoint="/uapi/domestic-stock/v1/trading/inquire-balance" if not is_irp else "/uapi/domestic-stock/v1/trading/pension/inquire-balance", + tr_id = "TTTC8434R" if not is_irp else "TTTC2208R" + params={ + "CANO": self.account["CANO"], + "ACNT_PRDT_CD": self.account["ACNT_PRDT_CD"], + "INQR_DVSN": "01" if not is_irp else "00", + "CTX_AREA_FK100": "", + "CTX_AREA_NK100": "", + } + if not is_irp: + params["AFHR_FLPR_YN"] = "N", + params["OFL_YN"] = "", + params["UNPR_DVSN"] = "01", + parmas["FUND_STTL_ICLD_YN"] = "N", + params["FNCG_AMT_AUTO_RDPT_YN"] = "N", + params["PRCS_DVSN"] = "00", return self._make_request_dict( - endpoint="/uapi/domestic-stock/v1/trading/inquire-balance", - tr_id="TTTC8434R", - params={ - "CANO": self.account["CANO"], - "ACNT_PRDT_CD": self.account["ACNT_PRDT_CD"], - "AFHR_FLPR_YN": "N", - "OFL_YN": "", - "INQR_DVSN": "01", - "UNPR_DVSN": "01", - "FUND_STTL_ICLD_YN": "N", - "FNCG_AMT_AUTO_RDPT_YN": "N", - "PRCS_DVSN": "00", - "CTX_AREA_FK100": "", - "CTX_AREA_NK100": "", - }, + endpoint=endpoint, + tr_id=tr_id, + params=params, ) def get_cash_available( From b905307f858345752725ee128ca88ffb81faad83 Mon Sep 17 00:00:00 2001 From: Seth Jeon Date: Tue, 4 Aug 2026 01:59:32 +0000 Subject: [PATCH 03/10] Postprocess IRP balance response for compatibility --- kis_agent/account/balance_query_api.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/kis_agent/account/balance_query_api.py b/kis_agent/account/balance_query_api.py index d6939a6..f449738 100644 --- a/kis_agent/account/balance_query_api.py +++ b/kis_agent/account/balance_query_api.py @@ -45,11 +45,16 @@ def get_account_balance(self) -> Optional[Dict]: parmas["FUND_STTL_ICLD_YN"] = "N", params["FNCG_AMT_AUTO_RDPT_YN"] = "N", params["PRCS_DVSN"] = "00", - return self._make_request_dict( + response = self._make_request_dict( endpoint=endpoint, tr_id=tr_id, params=params, ) + if is_irp: + # 일반계좌 `output2`: `[ResponseBodyoutput2]` + # IRP계좌 `output2`: `ResponseBodyoutput2` + response["output2"] = [response["output2"]] + return response def get_cash_available( self, stock_code: str = "005930" From 9ad0dfef16f5fdd473085af52e32fc3c0beef34f Mon Sep 17 00:00:00 2001 From: Seth Jeon Date: Tue, 4 Aug 2026 01:59:36 +0000 Subject: [PATCH 04/10] Implement query IRP possible order --- kis_agent/account/balance_query_api.py | 29 ++++++++++++++++---------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/kis_agent/account/balance_query_api.py b/kis_agent/account/balance_query_api.py index f449738..31acbb7 100644 --- a/kis_agent/account/balance_query_api.py +++ b/kis_agent/account/balance_query_api.py @@ -202,18 +202,25 @@ def inquire_psbl_order( ) -> Optional[Dict]: """매수가능 조회. ord_psbl_cash/max_buy_qty/ord_psbl_qty 반환.""" try: + is_irp = self.account["ACNT_PRDT_CD"] == "29" + endpoint="/uapi/domestic-stock/v1/trading/inquire-psbl-order" if not is_irp else "/uapi/domestic-stock/v1/trading/pension/inquire-psbl-order", + tr_id="TTTC8908R" if not is_irp "TTTC0503R", # 모의투자 변환은 client.make_request가 처리 + params={ + "CANO": self.account["CANO"], + "ACNT_PRDT_CD": self.account["ACNT_PRDT_CD"], + "PDNO": pdno, + "ORD_UNPR": str(price), + "ORD_DVSN": ord_dvsn, + "CMA_EVLU_AMT_ICLD_YN": "Y", + } + if not is_irp: + params["OVRS_JCLD_YN"] = "N" + else: + params["ACCA_DVSN_CD"] = "00" res = self.client.make_request( - endpoint="/uapi/domestic-stock/v1/trading/inquire-psbl-order", - tr_id="TTTC8908R", # 모의투자 변환은 client.make_request가 처리 - params={ - "CANO": self.account["CANO"], - "ACNT_PRDT_CD": self.account["ACNT_PRDT_CD"], - "PDNO": pdno, - "ORD_UNPR": str(price), - "ORD_DVSN": ord_dvsn, - "CMA_EVLU_AMT_ICLD_YN": "Y", - "OVRS_ICLD_YN": "N", - }, + endpoint=endpoint, + tr_id=tr_id, # 모의투자 변환은 client.make_request가 처리 + params=params, ) if res and res.get("rt_cd") == "0": return res.get("output", {}) From a652e0b169fb856e570f1dacacce894c4fe9e92d Mon Sep 17 00:00:00 2001 From: Seth Jeon Date: Tue, 4 Aug 2026 01:59:46 +0000 Subject: [PATCH 05/10] Remove incorrect comma resulting in tuple instead of str --- kis_agent/account/balance_query_api.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/kis_agent/account/balance_query_api.py b/kis_agent/account/balance_query_api.py index 31acbb7..b0eecf6 100644 --- a/kis_agent/account/balance_query_api.py +++ b/kis_agent/account/balance_query_api.py @@ -29,7 +29,7 @@ def __init__( def get_account_balance(self) -> Optional[Dict]: """계좌 잔고 조회. output1=보유종목, output2=요약(예수금/총평가/순자산).""" is_irp = self.account["ACNT_PRDT_CD"] == "29" - endpoint="/uapi/domestic-stock/v1/trading/inquire-balance" if not is_irp else "/uapi/domestic-stock/v1/trading/pension/inquire-balance", + endpoint="/uapi/domestic-stock/v1/trading/inquire-balance" if not is_irp else "/uapi/domestic-stock/v1/trading/pension/inquire-balance" tr_id = "TTTC8434R" if not is_irp else "TTTC2208R" params={ "CANO": self.account["CANO"], @@ -39,12 +39,12 @@ def get_account_balance(self) -> Optional[Dict]: "CTX_AREA_NK100": "", } if not is_irp: - params["AFHR_FLPR_YN"] = "N", - params["OFL_YN"] = "", - params["UNPR_DVSN"] = "01", - parmas["FUND_STTL_ICLD_YN"] = "N", - params["FNCG_AMT_AUTO_RDPT_YN"] = "N", - params["PRCS_DVSN"] = "00", + params["AFHR_FLPR_YN"] = "N" + params["OFL_YN"] = "" + params["UNPR_DVSN"] = "01" + params["FUND_STTL_ICLD_YN"] = "N" + params["FNCG_AMT_AUTO_RDPT_YN"] = "N" + params["PRCS_DVSN"] = "00" response = self._make_request_dict( endpoint=endpoint, tr_id=tr_id, @@ -203,8 +203,8 @@ def inquire_psbl_order( """매수가능 조회. ord_psbl_cash/max_buy_qty/ord_psbl_qty 반환.""" try: is_irp = self.account["ACNT_PRDT_CD"] == "29" - endpoint="/uapi/domestic-stock/v1/trading/inquire-psbl-order" if not is_irp else "/uapi/domestic-stock/v1/trading/pension/inquire-psbl-order", - tr_id="TTTC8908R" if not is_irp "TTTC0503R", # 모의투자 변환은 client.make_request가 처리 + endpoint="/uapi/domestic-stock/v1/trading/inquire-psbl-order" if not is_irp else "/uapi/domestic-stock/v1/trading/pension/inquire-psbl-order" + tr_id="TTTC8908R" if not is_irp else "TTTC0503R" # 모의투자 변환은 client.make_request가 처리 params={ "CANO": self.account["CANO"], "ACNT_PRDT_CD": self.account["ACNT_PRDT_CD"], From 37467eb1d718a045bcff02598c205c37b8a05923 Mon Sep 17 00:00:00 2001 From: Seth Jeon Date: Tue, 4 Aug 2026 01:59:54 +0000 Subject: [PATCH 06/10] Add missing param for IRP balance --- kis_agent/account/balance_query_api.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kis_agent/account/balance_query_api.py b/kis_agent/account/balance_query_api.py index b0eecf6..5329887 100644 --- a/kis_agent/account/balance_query_api.py +++ b/kis_agent/account/balance_query_api.py @@ -45,6 +45,8 @@ def get_account_balance(self) -> Optional[Dict]: params["FUND_STTL_ICLD_YN"] = "N" params["FNCG_AMT_AUTO_RDPT_YN"] = "N" params["PRCS_DVSN"] = "00" + else: + params["ACCA_DVSN_CD"] = "00" response = self._make_request_dict( endpoint=endpoint, tr_id=tr_id, From 85c471b83b3e81d65ad1871db15c4a4ea7709c6a Mon Sep 17 00:00:00 2001 From: Seth Jeon Date: Tue, 4 Aug 2026 01:59:59 +0000 Subject: [PATCH 07/10] Revert c1336c9 since IRP API doc is incorrect" --- kis_agent/account/balance_query_api.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/kis_agent/account/balance_query_api.py b/kis_agent/account/balance_query_api.py index 5329887..b51279e 100644 --- a/kis_agent/account/balance_query_api.py +++ b/kis_agent/account/balance_query_api.py @@ -47,16 +47,11 @@ def get_account_balance(self) -> Optional[Dict]: params["PRCS_DVSN"] = "00" else: params["ACCA_DVSN_CD"] = "00" - response = self._make_request_dict( + return self._make_request_dict( endpoint=endpoint, tr_id=tr_id, params=params, ) - if is_irp: - # 일반계좌 `output2`: `[ResponseBodyoutput2]` - # IRP계좌 `output2`: `ResponseBodyoutput2` - response["output2"] = [response["output2"]] - return response def get_cash_available( self, stock_code: str = "005930" From 02e47d20bfbad5c111e650125df7b826de35564b Mon Sep 17 00:00:00 2001 From: Seth Jeon <308413777+ssethj@users.noreply.github.com> Date: Wed, 12 Aug 2026 07:05:53 +0900 Subject: [PATCH 08/10] Fix account configuration key for stock accounts --- kis_agent/core/auth.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kis_agent/core/auth.py b/kis_agent/core/auth.py index e2277ff..57604b8 100644 --- a/kis_agent/core/auth.py +++ b/kis_agent/core/auth.py @@ -364,9 +364,9 @@ def changeTREnv( ): # 실전투자 선물옵션(파생) cfg["my_acct"] = _cfg.get("my_acct_future", "") elif svr == "prod" and product == "22": # 연금계좌 - cfg["my_acct"] = _cfg.get("my_acct__stock", "") + cfg["my_acct"] = _cfg.get("my_acct_stock", "") elif svr == "prod" and product == "29": # IRP. 주문 불가. 계좌조회/시세조회만 가능 - cfg["my_acct"] = _cfg.get("my_acct__stock", "") + cfg["my_acct"] = _cfg.get("my_acct_stock", "") elif svr == "vps" and product == "01": # 모의투자 주식투자, 위탁계좌, 투자계좌 cfg["my_acct"] = _cfg.get("my_paper_stock", "") elif svr == "vps" and product == "03": # 모의투자 선물옵션(파생) From 2cb8460160df344f019b108e260e9b498dc94bfd Mon Sep 17 00:00:00 2001 From: Seth Jeon <308413777+ssethj@users.noreply.github.com> Date: Wed, 12 Aug 2026 07:08:24 +0900 Subject: [PATCH 09/10] Modify params for balance query based on IRP Update parameter handling for balance query based on IRP status. --- kis_agent/account/balance_query_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kis_agent/account/balance_query_api.py b/kis_agent/account/balance_query_api.py index b51279e..2ddbe5a 100644 --- a/kis_agent/account/balance_query_api.py +++ b/kis_agent/account/balance_query_api.py @@ -211,7 +211,7 @@ def inquire_psbl_order( "CMA_EVLU_AMT_ICLD_YN": "Y", } if not is_irp: - params["OVRS_JCLD_YN"] = "N" + params["OVRS_ICLD_YN"] = "N" else: params["ACCA_DVSN_CD"] = "00" res = self.client.make_request( From 53a5b061b6a7d0e0b6eed371a5ff9322627f00e3 Mon Sep 17 00:00:00 2001 From: Seth Jeon Date: Tue, 11 Aug 2026 22:38:35 +0000 Subject: [PATCH 10/10] Reformat balance_query_api.py with black --- kis_agent/account/balance_query_api.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/kis_agent/account/balance_query_api.py b/kis_agent/account/balance_query_api.py index b51279e..3231a62 100644 --- a/kis_agent/account/balance_query_api.py +++ b/kis_agent/account/balance_query_api.py @@ -29,9 +29,13 @@ def __init__( def get_account_balance(self) -> Optional[Dict]: """계좌 잔고 조회. output1=보유종목, output2=요약(예수금/총평가/순자산).""" is_irp = self.account["ACNT_PRDT_CD"] == "29" - endpoint="/uapi/domestic-stock/v1/trading/inquire-balance" if not is_irp else "/uapi/domestic-stock/v1/trading/pension/inquire-balance" + endpoint = ( + "/uapi/domestic-stock/v1/trading/inquire-balance" + if not is_irp + else "/uapi/domestic-stock/v1/trading/pension/inquire-balance" + ) tr_id = "TTTC8434R" if not is_irp else "TTTC2208R" - params={ + params = { "CANO": self.account["CANO"], "ACNT_PRDT_CD": self.account["ACNT_PRDT_CD"], "INQR_DVSN": "01" if not is_irp else "00", @@ -200,9 +204,15 @@ def inquire_psbl_order( """매수가능 조회. ord_psbl_cash/max_buy_qty/ord_psbl_qty 반환.""" try: is_irp = self.account["ACNT_PRDT_CD"] == "29" - endpoint="/uapi/domestic-stock/v1/trading/inquire-psbl-order" if not is_irp else "/uapi/domestic-stock/v1/trading/pension/inquire-psbl-order" - tr_id="TTTC8908R" if not is_irp else "TTTC0503R" # 모의투자 변환은 client.make_request가 처리 - params={ + endpoint = ( + "/uapi/domestic-stock/v1/trading/inquire-psbl-order" + if not is_irp + else "/uapi/domestic-stock/v1/trading/pension/inquire-psbl-order" + ) + tr_id = ( + "TTTC8908R" if not is_irp else "TTTC0503R" + ) # 모의투자 변환은 client.make_request가 처리 + params = { "CANO": self.account["CANO"], "ACNT_PRDT_CD": self.account["ACNT_PRDT_CD"], "PDNO": pdno,