import { kisPost } from "@/lib/kis/client"; import { KisCredentialInput } from "@/lib/kis/config"; import { DashboardOrderSide, DashboardOrderType, } from "@/features/trade/types/trade.types"; /** * @file lib/kis/trade.ts * @description KIS 주식 주문/잔고 관련 API */ export interface KisOrderCashOutput { KRX_FWDG_ORD_ORGNO?: string; // 한국거래소전송주문조직번호 ODNO?: string; // 주문번호 ORD_TMD?: string; // 주문시각 } interface KisOrderCashBody { CANO: string; // 종합계좌번호(8자리) ACNT_PRDT_CD: string; // 계좌상품코드(2자리) PDNO: string; // 종목코드 ORD_DVSN: string; // 주문구분(00:지정가, 01:시장가...) ORD_QTY: string; // 주문수량 ORD_UNPR: string; // 주문단가 } /** * 현금 주문(매수/매도) 실행 */ export async function executeOrderCash( params: { symbol: string; side: DashboardOrderSide; orderType: DashboardOrderType; quantity: number; price: number; accountNo: string; accountProductCode: string; }, credentials?: KisCredentialInput, ) { const trId = resolveOrderTrId(params.side, credentials?.tradingEnv); const ordDvsn = resolveOrderDivision(params.orderType); const body: KisOrderCashBody = { CANO: params.accountNo, ACNT_PRDT_CD: params.accountProductCode, PDNO: params.symbol, ORD_DVSN: ordDvsn, ORD_QTY: String(params.quantity), ORD_UNPR: String(params.price), }; const response = await kisPost( "/uapi/domestic-stock/v1/trading/order-cash", trId, body, credentials, ); return response.output ?? {}; } function resolveOrderTrId(side: DashboardOrderSide, env?: "real" | "mock") { const isMock = env === "mock"; if (side === "buy") { // 매수 return isMock ? "VTTC0802U" : "TTTC0802U"; } else { // 매도 return isMock ? "VTTC0801U" : "TTTC0801U"; } } function resolveOrderDivision(type: DashboardOrderType) { // 00: 지정가, 01: 시장가 if (type === "market") return "01"; return "00"; }