
머리로 생각한 타점, 코드로 실행하다
안녕하세요. 내 계좌를 튼튼하게 다지는 [계좌 리팩토링] 자동매매 봇 만들기 시리즈 6편입니다. 지난 시간까지 우리는 봇에게 '눈'과 '귀'를 달아주었습니다. 4편에서는 내 계좌의 예수금 상태(REST API)를 파악했고, 5편에서는 시장의 실시간 시세(WebSocket)를 읽어내는 데 성공했습니다.
이제 드디어 봇에게 '손'을 달아줄 차례입니다. 우리가 설정한 로직(타점)이 왔을 때, 망설임이나 감정의 동요 없이 기계적으로 주식을 사들이는 '매수 주문(Buy Order)'을 구현해 보겠습니다.
시장가 vs 지정가: 봇에게 어떻게 명령할 것인가?
주문을 코드로 구현하기 전에, 증권사 API가 요구하는 주문의 형태를 이해해야 합니다. 자동매매에서 가장 많이 쓰이는 두 가지 주문 방식이 있습니다.
- 지정가 (Limit Order - 코드
00): "삼성전자 딱 80,000원에 1주 사줘. 안 오면 안 사도 돼." 가격을 지정하여 매수합니다. 원하는 가격에 살 수 있지만, 체결이 안 될 확률도 존재합니다. - 시장가 (Market Order - 코드
01): "가격 상관없어! 지금 당장 가장 빨리 팔려는 사람 주식을 1주 사줘!" 현재 호가창에 있는 최우선 매도 잔량을 즉시 긁어옵니다. 무조건 체결되지만, 예상보다 비싸게 살 위험이 있습니다.
초기 봇 개발 단계에서는 로직이 정상적으로 동작하는지(체결이 되는지) 확인하는 것이 중요하므로, '시장가(01)' 주문을 먼저 테스트해보는 것을 추천합니다.
주문 API의 핵심: POST 통신과 TR 코드
계좌를 조회하거나 시세를 확인할 때는 서버에서 데이터를 가져오기만 하는 GET 요청을 사용했습니다. 하지만 주식을 사고파는 행위는 내 계좌의 상태와 증권사의 DB를 '변경'하는 작업이므로 POST 방식의 HTTP 요청을 사용해야 합니다.
한국투자증권(KIS) 모의투자의 주식 현금 매수 TR 코드는 VTTC0802U 입니다. (실전 투자는 TTTC0802U로 다릅니다. 이 강좌는 철저히 모의투자를 기준으로 진행됩니다.)

Node.js 매수 주문 코드 구현하기
새로운 파일 buy_order.js를 만들고 아래 코드를 작성해 봅시다. (3편에서 만든 토큰 발급 로직이 준비되어 있어야 합니다.)
// (프로젝트 루트의 buy_order.js)
require('dotenv').config();
const axios = require('axios');
const { getAccessToken } = require('./get_token'); // 저장해둔 토큰 발급 함수
// 모의투자 URL 세팅
const BASE_URL = process.env.KIS_API_URL || 'https://openapivts.koreainvestment.com:29443';
/**
* 주식 매수 주문 함수
* @param {string} stockCode - 종목코드 (예: '005930')
* @param {number} orderQty - 주문 수량
* @param {number} orderPrice - 주문 단가 (시장가일 경우 무시됨)
* @param {string} orderType - 주문 구분 (00: 지정가, 01: 시장가)
*/
const buyStock = async (stockCode, orderQty, orderPrice, orderType = '00') => {
try {
const token = await getAccessToken();
// POST 요청 헤더 세팅
const headers = {
'Content-Type': 'application/json',
'authorization': `Bearer ${token}`,
'appkey': process.env.KIS_APP_KEY,
'appsecret': process.env.KIS_APP_SECRET,
'tr_id': 'VTTC0802U', // [모의투자] 주식 현금 매수 TR 코드
'custtype': 'P',
};
// POST 요청 바디(데이터) 세팅
const data = {
CANO: process.env.KIS_ACCOUNT_NUMBER, // 계좌번호 앞 8자리
ACNT_PRDT_CD: '01', // 계좌상품코드 (통상 01)
PDNO: stockCode, // 종목코드
ORD_DVSN: orderType, // 주문구분 (00: 지정가, 01: 시장가)
ORD_QTY: orderQty.toString(), // 수량은 문자열로 전달
// 시장가(01)일 경우 가격은 '0'으로 보내야 함
ORD_UNPR: orderType === '01' ? '0' : orderPrice.toString(),
};
console.log(`\n[주문 전송] ${stockCode} ${orderQty}주 매수 시도 중... (타입: ${orderType})`);
// axios.post 메서드 사용 (URL, Body데이터, 헤더)
const response = await axios.post(`${BASE_URL}/uapi/domestic-stock/v1/trading/order-cash`, data, { headers });
const result = response.data;
// 응답 결과 파싱
if (result.rt_cd === '0') {
console.log(`✅ [주문 성공] 처리 메시지: ${result.msg1}`);
console.log(`✅ [주문 번호]: ${result.output.ODNO}`); // 나중에 주문 취소/정정 시 필요
} else {
console.error(`❌ [주문 실패] 에러 코드: ${result.rt_cd}`);
console.error(`❌ [실패 사유]: ${result.msg1}`);
}
} catch (error) {
console.error('❌ [서버 통신 에러 발생]');
if (error.response) {
console.error(error.response.data);
} else {
console.error(error.message);
}
}
};
// 실습 실행: 삼성전자(005930) 1주를 '시장가(01)'로 매수!
// (장이 열려있는 시간에만 정상 체결 메시지가 나옵니다)
buyStock('005930', 1, 0, '01');
코드 리팩토링: 실전 투입 전 필수 체크리스트
코드를 실행해서 "주문 성공" 메시지를 보셨나요? 축하합니다! 하지만 진정한 계좌 리팩토링은 단순히 주문이 들어가는 것에서 끝나지 않습니다. 봇이 폭주하여 내 계좌를 거덜내지 않도록 안전장치를 만들어야 합니다.
- 예수금 확인 연동: 주문을 넣기 전, 4편에서 만든 '잔고 조회' 함수를 먼저 실행하여
D+2 활용금이 매수하려는 금액보다 큰지 반드시 확인하는if문을 추가해야 합니다. - 중복 주문 방지: WebSocket으로 5편에서 시세를 받을 때, 조건이 만족되었다고 매 밀리초마다 주문을 쏘면 순식간에 수십 건이 체결될 수 있습니다. '주문 중(isOrdering = true)'이라는 상태 값을 변수로 두어, 한 번 주문이 들어가면 결과가 나올 때까지 다음 주문을 블록(Block)하는 로직이 필요합니다.
마무리 및 다음 편 예고
드디어 봇이 우리를 대신해 시장에 첫 발을 내디뎠습니다. 매수하는 방법을 알았으니, 이제 수익을 확정 짓는 '매도(Sell)' 로직도 구현해야겠죠?
다음 7편에서는 매수와 거의 동일하지만 몇 가지 주의할 점이 있는 '주식 현금 매도 주문 구현 및 수익률 계산 로직'에 대해 알아보겠습니다. 진정한 시스템 트레이더의 길, 계속 함께해 주세요!
⚠️ 주의사항 (면책 조항)
자동매매 주문 로직 테스트는 반드시 증권사의 '모의투자' 환경에서 소액으로 수차례 검증을 거쳐야 합니다. 코드의 오타나 논리적 오류로 인한 폭포수 주문(무한루프) 등 금전적 손실이 발생할 수 있으며, 이에 대한 모든 책임은 개발자 본인에게 있습니다.
'🛠️ Dev & Tools (투자 도구 개발)' 카테고리의 다른 글
| [계좌 리팩토링] 8편. 24시간 잠들지 않는 봇! PM2와 node-cron으로 무중단 자동화 완성하기 (0) | 2026.05.22 |
|---|---|
| [계좌 리팩토링] 7편. 수익의 완성! Node.js 주식 매도 주문 및 수익률 자동 계산 (0) | 2026.05.20 |
| [계좌 리팩토링] 5편. 뚝딱뚝딱 호가창 연동! Node.js 실시간 시세 조회 (WebSocket) (0) | 2026.05.18 |
| [계좌 리팩토링] 4편. 내 계좌 정보, 실시간으로 완벽하게 파싱하기 (REST API) (0) | 2026.05.15 |
| [계좌 리팩토링] 3편. 매매 봇의 심장을 켜다! KIS API 토큰(Access Token) 발급 및 캐싱 전략 (0) | 2026.05.14 |