레이블이 클로드인 게시물을 표시합니다. 모든 게시물 표시
레이블이 클로드인 게시물을 표시합니다. 모든 게시물 표시

[주식 클로드 자동매매 프로젝트] 제2편. 데이터 인프라 구축 — 모델보다 데이터가 먼저다

 머신러닝 모델을 이야기하기 전에, 그 모델이 먹는 데이터가 어디서 어떻게 왔는지부터 정직하게 밝혀야 한다. 이 프로젝트에서 가장 많은 시간이 들어간 부분은 화려한 모델 튜닝이 아니라, "내가 정말 그 데이터를 갖고 있는가"를 확인하고 고치는 작업이었다.


무엇을 쌓았나

MariaDB에 stock이라는 데이터베이스를 만들고, R 스크립트로 여러 소스에서 데이터를 긁어 다음 테이블들을 채웠다.


price_daily (일봉 시세): 네이버 금융 API에서 2014년부터, 종목당 최대 약 11년치

market_info (PER/PBR/EPS/BPS/시가총액): 2015년부터. 다만 이건 실제 재무제표 값이 아니라 가격 기반 역산 근사치라는 걸 분명히 해야 한다

disclosure_dart (DART 전자공시): 2025년 9월부터 완전 백필, 필요하면 개별 기업 단위로 11.7년치까지 백필 가능함을 확인

news / news_sentiment (뉴스 원문 + 감성 점수): 2025년 9월부터

investor_flow (외국인·기관 수급): 여기서 큰 벽에 부딪혔다 — 아래 설명

short_selling / short_balance (공매도 거래·잔고): 2021년 9월부터, KRX의 봇 차단을 우회해서 5년치 확보

sentiment_daily: 가격모멘텀·거래량·수급·공매도·신용잔고·뉴스감성·시장전체 등 8개 카테고리를 종합한 심리 점수. 실제로는 확보된 카테고리만큼만 가중치를 동적으로 재분배해서 계산한다 (없는 데이터를 0으로 채우지 않는다는 원칙)

trading_calendar: KRX 개장일 캘린더. 이후 모든 자동화 크론이 "오늘이 개장일인가"를 판단하는 기준이 된다

수급 데이터의 구조적 한계 — 포기할 건 포기한다

외국인·기관 수급 데이터는 처음부터 야심 차게 장기 백필을 시도했다. 그런데 네이버가 제공하는 API 구조 자체가 종목당 최근 5영업일치만 준다는 걸 확인했다. KRX의 로그인 없는 접근 경로까지 뒤져봤지만, 개별 종목의 장기 투자자별 매매 동향은 KRX 공식 Open API에도 서비스 자체가 없었다.


결론은 "포기하고 매일 조금씩 쌓는다"였다. 장기 백필이 불가능하다는 걸 인정하고, 매일 크론으로 최근 5일치를 누적해서 시간이 지나면서 자연스럽게 이력을 쌓는 방식으로 전환했다. 이건 실패가 아니라 "안 되는 걸 억지로 되게 하려고 시간을 쓰지 않는다"는 결정이었다.


실제로 만난 버그들

BACKFILL_MONTHS 버그 — 최신 1행만 쌓이고 있었다

업로드 스크립트가 환경변수를 지정하지 않으면 기본적으로 "최신 1행만" DB에 올리도록 설계돼 있었다. 이 사실을 모른 채 몇 주가 지나서, 46개 종목 중 43개가 시세 데이터 딱 하루치만 갖고 있는 상태였다. 원인을 찾아 11년치 전체를 다시 적재했다.

뉴스가 페이지당 1건만 들어오던 버그

네이버 뉴스 API 응답이 [{total, items:[1건]}, {total, items:[1건]}, ...] 형태로, 기사마다 개별 wrapper를 갖는 구조였다. 그런데 파싱 코드가 js$items[[1]]로 첫 번째 항목만 꺼내고 있었다 — 페이지당 20건 중 딱 1건만 가져온 것이다. 이 버그 때문에 뉴스 테이블이 242건에 머물러 있었다. 고친 뒤 재수집하니 22,997건으로 늘었다.

KRX IP 차단 — 욕심이 부른 사고

공매도 순보유잔고 데이터를 대량으로 긁어오던 중, KRX가 "자동화 수단을 통한 비정상 대량조회"를 탐지해 IP를 1일간 차단했다. 날짜당 2회(코스피/코스닥)씩 약 1,200영업일을 0.15초 간격으로 연속 요청한 게 원인으로 보인다. 요청 간격을 늘리고, 차단 감지 시 즉시 중단하는 안전장치와 "이미 받은 데이터 다음부터 이어받는" 재개 로직을 추가했다.

12자리 ISIN 코드 체크디짓 하드코딩 버그

6자리 종목코드를 국제 표준 12자리 ISIN 코드로 변환할 때, 체크디짓(검증숫자)을 매번 "003"으로 고정해놓은 코드가 있었다. 삼성전자는 우연히 체크디짓이 3이라 통과됐지만, 한화오션을 비롯한 대다수 종목은 실제 체크디짓이 다른데도 조용히 0건으로 실패하고 있었다. Luhn 알고리즘으로 정확히 계산하도록 고쳤다.

지주사-자회사 뉴스가 서로 뒤섞이는 문제

news 테이블의 기본키가 기사ID 하나뿐이었다. 그런데 지주사와 자회사를 함께 언급하는 기사는 네이버가 여러 종목의 뉴스피드에 같은 기사ID로 노출하는데, DB에는 먼저 들어온 종목 하나에만 저장되고 나머지는 조용히 무시됐다. 실제로 아모레퍼시픽(090430)의 6개월 뉴스를 새로 수집했더니 1,290건 전부가 이미 다른 종목(대부분 지주사인 아모레퍼시픽홀딩스)에 귀속돼 있어서 신규로 남은 게 하나도 없었다. 아모레퍼시픽은 사실상 자체 뉴스 데이터가 거의 없는 상태였던 것이다.

왜 이 이야기부터 하는가

모델 튜닝 이야기를 먼저 하고 싶은 유혹이 있었지만, 순서를 지키기로 했다. 이 프로젝트에서 배운 첫 번째 교훈이 바로 이거다.


코드가 정상 종료됐다는 것과, 데이터가 맞게 들어갔다는 것은 다른 이야기다.


exit code 0을 보고 "완료됐다"고 믿었다가, 나중에 "사실 하루치만 있었다" "1건만 들어오고 있었다" "체크디짓이 틀려서 대부분 실패하고 있었다"는 걸 뒤늦게 발견한 경험이 여러 번 있었다. 이후 모든 검증 단계에서 "실행이 성공했다"와 "결과가 맞다"를 항상 분리해서 확인하는 습관이 여기서 생겼다.


다음 편에서는 이 데이터를 갖고 처음으로 randomForest 모델을 학습시킨 이야기, 그리고 애초에 왜 이 모델을 선택했는지를 다룬다.


(다음 편: 왜 randomForest인가 — 모델의 정의와 선택 이유)

[주식 클로드 자동매매 프로젝트] 제1편. 프로젝트를 시작한 이유와 전체 여정 개관

 나는 누구인가

  보전(설비 정비) 조직에서 25년을 일했고, 지금은 용접기 담당자다. 코딩은 업무의 일부가 아니었지만, RStudio로 데이터를 다루는 게 주특기가 됐다. 어느 시점부터 "이 도구로 내 개인 투자 판단도 데이터 기반으로 해볼 수 있지 않을까"라는 생각이 들었다.


주식 투자 경험이 아주 많은 것도 아니고, 화려한 금융공학 배경이 있는 것도 아니다. 그냥 데이터를 다룰 줄 아는 사람이 "국내 주식 중에서 살 만한 종목을 어떻게 데이터로 골라낼 수 있을까"라는 질문에서 시작한 프로젝트다.


목표를 처음부터 명확히 했다

시작할 때 세운 원칙은 세 가지였다.


AUC 0.7이라는 숫자에 억지로 맞추지 않는다. 모델이 실제로 예측력이 있는지 확인하는 게 목적이지, 특정 숫자를 만드는 게 목적이 아니다.

단일 train/test 분할을 믿지 않는다. 여러 연도에 걸친 walk-forward(확장윈도우) 검증으로 우연한 결과와 진짜 신호를 구분한다.

모델은 매매 신호가 아니라 보조 스코어다. 예측 확률 자체를 매수 버튼으로 쓰지 않고, 실제 돈이 오가는 매매 규칙(손절, 현금 관리, 종목 수 제한 등)과 분리해서 설계한다.

이 세 가지 원칙이 이후 한 달간의 모든 결정에 계속 등장한다. 특히 세 번째 원칙 때문에, 이 시리즈는 "AI가 주식을 맞췄다"는 이야기가 아니라 "약한 신호를 어떤 운영 규칙으로 감싸야 실제로 쓸모 있어지는가"에 관한 이야기가 됐다.


전체 여정 지도

이 시리즈는 실제 개발 순서를 그대로 따라간다.


데이터 인프라 (2편): DB에 가격·공시·뉴스·수급 데이터를 쌓는 과정에서 발견한 버그들. 화려한 부분은 아니지만 가장 먼저, 가장 오래 걸린 작업이다.

모델링 (3~6편): randomForest를 선택한 이유, walk-forward 검증 설계, 그리고 시도했다가 실패한 개선안들.

포트폴리오 운영 규칙 (7~9편): 모델의 약한 신호를 실제 매매 규칙으로 감싸는 과정. 버려진 아이디어가 채택된 아이디어보다 훨씬 많다.

자동매매 (10~11편): 키움증권 API 연동, 그리고 실전 배포 전에 발견한 위험한 버그들.

부수적 실험과 교훈 (12편): 채택되지 않았지만 방법론적으로 남길 가치가 있는 실험들, 그리고 전체 과정에서 얻은 일반화 가능한 교훈.

미리 말해둘 것

이 시스템은 이 글을 쓰는 시점(2026년 9월 27일)까지 실제 주문을 단 한 건도 낸 적이 없다. 자동매매 코드는 완성 단계지만 execution.enabled=false 상태로 잠겨 있고, 활성화하려면 사람이 직접 서명해야 하는 8개의 안전장치 중 아직 2개가 남아 있다. 그리고 나는 이걸 "아직 못 끝냈다"가 아니라 "제대로 하고 있다"는 증거로 본다. 그 이유는 이 시리즈를 끝까지 읽으면 이해가 될 것이다.


다음 편에서는 이 모든 것의 출발점, 데이터 인프라 구축 이야기부터 시작한다.


(다음 편: 데이터 인프라 구축 — 모델보다 데이터가 먼저다)

[주식 클로드 자동매매 프로젝트] 제2편. 데이터 인프라 구축 — 모델보다 데이터가 먼저다

 머신러닝 모델을 이야기하기 전에, 그 모델이 먹는 데이터가 어디서 어떻게 왔는지부터 정직하게 밝혀야 한다. 이 프로젝트에서 가장 많은 시간이 들어간 부분은 화려한 모델 튜닝이 아니라, "내가 정말 그 데이터를 갖고 있는가"를 확인하...