[주식 클로드 자동매매 프로젝트] 제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개가 남아 있다. 그리고 나는 이걸 "아직 못 끝냈다"가 아니라 "제대로 하고 있다"는 증거로 본다. 그 이유는 이 시리즈를 끝까지 읽으면 이해가 될 것이다.


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


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

공무 스케줄 AI Agem에 대한 생각

     지금 상황이 아비 규환이다.  어느 부서든 회사가 인수 합병되고 나서  투자를 기획하는 경영기획이 특히 않이 정신이 없고, 우리부서도 전부 미국 필리 조선소로 인원이 나가 있어,  사실상 10년 이상 고기량자는 거의 없다. 

 우리부서에 남아 있는 사람들도 오리지널 사무실 엔지니어들도 정년연장  또는 내년 정년 하는 시니어 들 뿐이다. 

정년연장 하시는 분들은 일단 특정 이슈 때문에 남아 있고 내년에 정년 퇴직 하시는 분도  사실상 업무에 대한 인수인계 수준이다. 

그리고 이것 저것  자료를 작성 해달라고 하는 경영진 들이 너무 많다.    투자 내용을 집계 하였는데, 그거 보고 하면 경영진 마음에 들지 않는다고, 다시 재작성 하라고 하면,  우리와 같이 투자가 많은 조직은 계속 같은 작업을 많이 한다. 

특히 지금 챙기는 것은 투자 미집행 사유에 대해서 많이 챙기는데, 어찌 되었든 이것 때문에 계속 소모적인 일에만 집중되어 있다. 

나에게는 이슈가 많이 될 만 한 것 특히  제조총괄장이 가동율에 신경을 많이 쓰는 인디로봇은 더욱더 그러하다.   평소에 하던 일이 바쁜데 특정 부품이 없어서 가동을 못한다는 이야기가 임원 사이에서 왔다갔다 하면,  중간관리자 파트장, 팀장이 정신이 없다. 

부서 공통관리  주간업무회의록, 투자주간업무회의록,  돌발 적인 투자 요청 업무,  ISO9001 품질 경영시스템 그리고,  AI 자동 용접설비 설비 특히 이건 경영진 KPI 로 등록 되어 있다,  핸드캐리형 인디로봇은 고장이 높아 신경써야 할 포인트가 너무 많다.   간접경비 계획을 수립 하여야 하고,  특히 종합생산성 향상은 보고 2주전 부터 공지가 오고, 보고 자료가 완성 될때 까지 계속 수정 해야 하는 업무이다.  

그리고 용접기 관련 OCR 시스템 개발 미래 준비를 위한 IOT 관련 진동분석에 대한 예진 보전에 대한 일들이 아주 산더미 처럼 쌓여 있다. 

신규 전입 사원 (신규, 경력)은 공통 업무에 대한 대응이 너무나 늦다.  

나는 운영에서 18년 근무 하였고, 현재 부서에서 근무한지 7년 정도 되었다,  예전에는 공통 업무를 어느정도 베테랑 사원들이 하였는데,  지금은 나 혼자 전부 떠 앉는다. 


  평소에 하던 일대로 일을 진행 하게 되면,  모든일에 대한 것의 우선 순위는 다른 사람들의 독촉 그리고,  이슈가 터진일에만 몰두 하게 되어서 일의 효율성이 떨어지고 해야할 Activity가 많아 지면,  결국 일에서  구멍이 생기는것은  다반사이고,  구멍이 생기면 중간 관리자들과 갈등이 생길수 밖에 없다. 

따라서 나는 Copilot AI Agent 기반으로 Planner를 사용해서 이것을  기반으로 해서,   오늘/내일/어제 일정뭐야,월요일 일정 뭐야, 화요일 일정 뭐야, 이번주 일정이 뭐야 다음주 일정이 뭐야를  자연어로 질문 하게 되면,  이것을 정리 하여, 아래와 같이 상황에 대해서 이야기 해준다. 

작업명, 시작,기한, 상태 우선순위를 보여 주며  아래와 같은 예시를 보여준다. 

작업명, 시작은 별다른 아이콘이 안뜨는데,  기한은 지나면, 빨간색 아이콘, 상태는 미시작은 원형 아이콘, 진행중이면, 진행 중이라는 파란색 아이콘이 뜬다.  그리고 우선순위에 따라서 긴급이면,  빨간색 아이콘이 뜨면, 중요나 보통은 노란색 아이콘이 뜬다.

즉 Planner에서 확인 하였던 사항이 위와 같이 오늘 일정이 뭐야 하면 중요도 진행상태, 기한이 지난것,  우선순위에 따라서 다르게 보여 준다. 

그래서 이 Agent를 사용할 때 마다, 일이 들어오고, 끝나는 것이 있으면, Planner에 기록하고, 오늘 일정이 뭐야를 계속 질의를 하여 모니터링 하여야,  현재의 상황을 파악하고 업무에 적용 하여, 상황에 대한 대응이 빠르고,  일을  모르고 지나치게 되는 일이 없게 되어 업무의 스트레스도 줄이고 과부하 상황에서 일을 효율적으로 할 수 있다.

  


css cheat sheet 클래스 선택자, margin(마진), display , center 조정 간단한 구성 요소

 앞에서는 html의 간단한 sheet를 소개 하였습니다.   html은  주로 골격을 나타나는 것이라, 디자인을 하는데는 css로 하여야 합니다. 

아래 코드와 같이 css 관련 하여 매우 간단하게 코딩 하겠습니다. 


  • body 부분의 css 코딩 

 body {

  background:yellow;

  color:blue;

  font-size : 20px;

  font-weight:liter;

  text-align:center;

  margin-top: 10px;  

}

  • html 코딩     

  <html>

  <head>

    <link rel="stylesheet" href="style.css" />

  </head>

  <body>

    Please accept ou cokkies!

  </body>

</html>


 결과 
  


  • 클래스 선택자(class selector) css 코딩
.main {
  margin-top: 100px;
}

.log-img {
  display: block;
  width: 380px;
}

.search-input {
  display: block;
  width: 480px;
}

  • 클래스 선택자(class seledctor) html 코딩

  <html>

  <head>

    <link rel="stylesheet" href="style.css" />

  </head>

  <body>

    <div class="main" align = "center">

      <img

        class="log-img"        src="https://www.google.co.kr/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png"

        width="100%"

      />

      <input class="search-input" type="text" />

      <div>

      </div>

    </div>

  </body>

</html>

 

  • margin(마진)의 css 코딩 

body {

  margin: 0;

}


.red {

  background: #c71226;

  height: 100px;

/*  margin-top: 10px;

  margin-left: 10px;

  margin-right: 10px;*/

}


.blue {

  background: #0d1b88;

  height: 100px;

   margin-top: 20px;

  margin-bottom: 20px;

}


.green {

  background: #397327;

  height: 100px;

}

  • margin(마진)의 html 코딩 

<html>

  <head>

    <link rel="stylesheet" href="style.css" />

  </head>

  <body>

    <div class="red"></div>

    <div class="blue"></div>

    <div class="green"></div>

  </body>

</html>

결과




  •  구글 main page 마진과 넒이 조정 css 코딩

.main {
  margin-top: 50px;
}

.log-img {
  display: block;
  width: 200px;
  margin-bottom: 20px;
}

.search-input {
  display: block;
  width: 400px;
}

  • 구글 main page 마진과 넒이 조정 html 코딩

<html>

  <head>

      <link rel="stylesheet" href="style.css" />

  </head>

  <body>

    <div class="main">

      <img   class = "log-img"   src="https://www.google.co.kr/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png"

        width="100%"

      />

      <input width="100%" type="text" />

    </div>

  </body>

</html>

결과


  •  margin을 이용한 center 조정 css

img{
  display:block;
  width:200px;
  margin-left:auto;
  margin-right:auto;    
}

  •  margin을 이용한 center 조정 html

 <html>

  <head>

     <link rel="stylesheet" href="style.css" />

  </head>

  <body>

    <img src ="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyygEBHnnwLxf2fLCYQZZjTKXCL2n87uhgG3k9vowLJsMCslhwKv_L010V6lgNCYdg8W7iqfUgnepSlO08F9dRx4gMvnQ6c6In5j6kd1wQK8yYy6ExrX6j-usLbZHTw-TXv587bq7gvZyqfzvY3vIgsPE2tAe-BIZIjvShxHPn53Yuqu-pv2lFBiRNV3c7/w263-h213/%EC%BA%A1%EC%B2%98.JPG">

  </body>

</html>

결과





 

이미지 파일들 메일 보낼때 사용

 메일을 보낼때 사용하는 이미지 파일들임


























html cheat sheet 헤드라인, 문단소스, 이미지 소스, 입력 소스, 하이퍼링크, html 구조, 목록

  html 코딩의 기본 개념만 정리 하였습니다. 

html 코딩은  웹페이지에  기본적으로 골격을 나타낸 것입니다. 

이건은  간단한 사항이라  별도의 텍스트 없이  내용만 간단히 처리 하겠습니다. 


  •  헤드라인과  문단 소스 
 <h1>humanmans have reache Mars</h1>

 <h3>he Sarship rocket successfully landed on th red plant this moning.</h3>

 <p>
   After a 115 days lon journy, th crew of finally arrived to their desination.
   This is the first time humans have set foot on a planet other than Earth
 </p>

    결과 
 


아래의 그림은  이미지 소스를 링크 시키기 위한  참고 그림 입니다. 





  • 이미지 소스 
      원래는 서버에 있는 사진으로 하여야 하나,  사진이 없으므로,  위의 있는 그림의 URL을 링크 시켜 이미지 소스를 걸었습니다. 
 

<h1>humanmans have reache Mars</h1>

<h3>he Sarship rocket successfully landed on th red plant this moning.</h3>

<img
  src="https://scx2.b-cdn.net/gfx/news/2021/a-couple-of-trainee-as-1.jpg"
  width="100%"
/>

<p>
  After a 115 days lon journy, th crew of finally arrived to their desination.
  This is the first time humans have set foot on a planet other than Earth
</p>

<img  src="https://blogger.googleusercontent.com/img/a/AVvXsEiTX7ZMBy8hgCUYGBCqiBX5CWHQhctWh9ow_zAJDqIaUNlLML08nUQoYGqAY0AQqls_U2v7_tID8oO2vUCzErms-ktMFE9KbNJRki-5oaSmorCzPaT3vo5SBF_9oBj4eHKmvcM6uGBxAAIf_0DZDwNOnbxdB0ZqJJ8qsmUF_J82errZNWdJrelQke8Wx9D8"
  width="100%"
/>"
 
  결과 



  • 버튼 소스
<h1>Welcome!</h1>
<p>You have been granted acess to the platform.
  Please create an account.
</p>

<button>Sign up!</button>

       결과

 


 

  • 아이디 패스워드  파일선택  버튼 
<h1>Welcome!</h1>
<p>You have been granted acess to the platform. Please create an account.</p>

<input type="text" placeholder="Enter username" />
<input type="password" placeholder="Enter password" />
<input type="file" />
<button>Sign up!</button>
   결과
  • 앵커 태그 다른 페이지를 링크 걸 때
<h1>My work</h1>
<h2>Project 1: Google.com</h2>
<p>I built this one as a part of HTML&CSS</p>
<p>
  Check out the live demo
  <a href="https://google.com/" target="_blank">here </a>
</p>
   
결과 

  • 구글 페이지로 살펴 본 구조 정리 
       스타일 시트 때문에  코드가 길어 졌습니다.   이건은 나중에 추가 정리 하겠습니다. 

<!doctype html>
<html>
  <head>
    <style>
      body,
      html {
        margin: 0;
        padding: 0;
      }

      img {
        width: 30%;
        display: block;
        margin: 100px auto 20px;
        min-width: 272px;
      }

      input {
        box-sizing: border-box;
        display: block;
        border-radius: 24px;
        border: 1px solid rgb(223, 225, 229);
        height: 44px;
        margin: 0 auto 29px;
        max-width: 564px;
        width: 90%;
        padding-left: 30px;
        font-size: 16px;
      }

      button {
        box-sizing: border-box;
        margin-top: 0;
        padding: 0 16px;
        font-size: 14px;
        height: 36px;
        background-color: #f8f9fa;
        border: 1px solid #f8f9fa;
        cursor: pointer;
      }

      button:first-of-type {
        margin-right: 8px;
        margin-left: calc(50% - 131.5px);
      }

      button::hover {
      }

      p {
        margin-top: 40px;
        text-align: center;
      }

      a {
      }
    </style>
  </head>

  <body>
    <img
      src="https://www.google.co.kr/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png"
      width="100%"
    />
    <input width="100%" type="text" />
    <button>Google Search</button>
    <button>I'M Feeling Lucky</button>
  </body>
</html>


결과 





  • 리스트 목록 나열하기 

<!DOCTYPE html>
<html>
  <head> </head>

  <body>
    <h1>Beijing Olympics</h1>
    <ui>
      <li>Norway</li>
      <li>Germay</li>
      <li>China</li>
      <li>US</li>
    </ui>
  </body>
</html> 


  결과 

   


C 언어 문자 및 숫자 형 보기 char int

   아래의 코드는 코딩자율 학습 나도 코딩의 C언어 입문의 1장 코드를 인용 한것이다. 

나중에  C 언어 치다가  잘 모를 때,  사용  할 수 있어 좋을 것 같아서 기록 한다. 


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

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