🛠️ Dev & Tools (투자 도구 개발)

[계좌 리팩토링] 6편. 드디어 실전! Node.js로 주식 매수 주문 자동화하기

코딩버핏 2026. 5. 19. 20:28

Node.js로 주식 매수 주문 자동화

 

머리로 생각한 타점, 코드로 실행하다

안녕하세요. 내 계좌를 튼튼하게 다지는 [계좌 리팩토링] 자동매매 봇 만들기 시리즈 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');

코드 리팩토링: 실전 투입 전 필수 체크리스트

코드를 실행해서 "주문 성공" 메시지를 보셨나요? 축하합니다! 하지만 진정한 계좌 리팩토링은 단순히 주문이 들어가는 것에서 끝나지 않습니다. 봇이 폭주하여 내 계좌를 거덜내지 않도록 안전장치를 만들어야 합니다.

  1. 예수금 확인 연동: 주문을 넣기 전, 4편에서 만든 '잔고 조회' 함수를 먼저 실행하여 D+2 활용금이 매수하려는 금액보다 큰지 반드시 확인하는 if 문을 추가해야 합니다.
  2. 중복 주문 방지: WebSocket으로 5편에서 시세를 받을 때, 조건이 만족되었다고 매 밀리초마다 주문을 쏘면 순식간에 수십 건이 체결될 수 있습니다. '주문 중(isOrdering = true)'이라는 상태 값을 변수로 두어, 한 번 주문이 들어가면 결과가 나올 때까지 다음 주문을 블록(Block)하는 로직이 필요합니다.

마무리 및 다음 편 예고

드디어 봇이 우리를 대신해 시장에 첫 발을 내디뎠습니다. 매수하는 방법을 알았으니, 이제 수익을 확정 짓는 '매도(Sell)' 로직도 구현해야겠죠?

다음 7편에서는 매수와 거의 동일하지만 몇 가지 주의할 점이 있는 '주식 현금 매도 주문 구현 및 수익률 계산 로직'에 대해 알아보겠습니다. 진정한 시스템 트레이더의 길, 계속 함께해 주세요!

⚠️ 주의사항 (면책 조항)

자동매매 주문 로직 테스트는 반드시 증권사의 '모의투자' 환경에서 소액으로 수차례 검증을 거쳐야 합니다. 코드의 오타나 논리적 오류로 인한 폭포수 주문(무한루프) 등 금전적 손실이 발생할 수 있으며, 이에 대한 모든 책임은 개발자 본인에게 있습니다.