feat: isolate strategy-owned KIS balances
This commit is contained in:
@@ -138,6 +138,7 @@ class KISBroker:
|
||||
"appkey": self._app_key,
|
||||
"appsecret": self._app_secret,
|
||||
"tr_id": tr_id,
|
||||
"custtype": "P",
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
}
|
||||
|
||||
@@ -343,6 +344,49 @@ class KISBroker:
|
||||
out.append(BalanceItem(symbol=symbol, hldg_qty=qty))
|
||||
return out
|
||||
|
||||
def get_available_cash(self, *, price_check_code: str = "005930") -> int:
|
||||
"""Return KIS cash-only buy capacity (`nrcvb_buy_amt`).
|
||||
|
||||
This is intentionally separate from ``BrokerPort``. An account
|
||||
compatibility service may use it to refresh per-strategy portfolio
|
||||
budgets without teaching the domain/Core about mixed manual holdings.
|
||||
"""
|
||||
cano, product = self._account()
|
||||
params = {
|
||||
"CANO": cano,
|
||||
"ACNT_PRDT_CD": product,
|
||||
"PDNO": str(price_check_code).zfill(6),
|
||||
# KIS recommends market-order mode when checking cash-only buying
|
||||
# capacity so the symbol's margin ratio is reflected.
|
||||
"ORD_UNPR": "0",
|
||||
"ORD_DVSN": "01",
|
||||
"CMA_EVLU_AMT_ICLD_YN": "Y",
|
||||
"OVRS_ICLD_YN": "N",
|
||||
}
|
||||
try:
|
||||
headers = self._headers("VTTC8908R" if self._mock else "TTTC8908R")
|
||||
response = httpx.get(
|
||||
f"{self._base_url}/uapi/domestic-stock/v1/trading/inquire-psbl-order",
|
||||
headers=headers,
|
||||
params=params,
|
||||
timeout=self._timeout,
|
||||
)
|
||||
response.raise_for_status()
|
||||
payload = response.json()
|
||||
except (httpx.HTTPError, KeyError, TypeError, ValueError):
|
||||
raise BrokerBalanceError("transport_failed") from None
|
||||
if not isinstance(payload, dict):
|
||||
raise BrokerBalanceError("malformed_response")
|
||||
if str(payload.get("rt_cd")) != "0":
|
||||
raise BrokerBalanceError("broker_rejected")
|
||||
output = payload.get("output")
|
||||
if not isinstance(output, dict):
|
||||
raise BrokerBalanceError("malformed_response")
|
||||
amount = _safe_int(output.get("nrcvb_buy_amt"))
|
||||
if amount is None or amount < 0:
|
||||
raise BrokerBalanceError("malformed_response")
|
||||
return amount
|
||||
|
||||
def get_current_price(self, symbol: str, market: str = "J") -> Optional[Decimal]:
|
||||
"""Current traded price `stck_prpr` via KIS inquire-price (REQ-038, REQ-118).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user