[stock101] KIS 코스피 코스닥 종목 정보 매일 최신화하기 - 3일차

2026. 1. 21. 23:06·Archive(완료된 내용)/포트폴리오 강화

단순히 "종목 정보를 넣는다"는 생각으로 시작했지만, 실제 데이터를 다루다 보니 고려해야 할 변수가 많았습니다. 개발 과정에서 마주한 고민과 이를 해결하기 위한 시스템 구조를 정리합니다.


🚀 개발 비하인드: 왜 '단순 저장' 이상이 필요했나?

처음에는 단순히 종목 마스터를 한 번 가져와 DB에 넣으면 끝날 줄 알았습니다. 하지만 실제 시장은 생각보다 훨씬 역동적이었습니다.

  1. "아, 신규 상장이 있구나!" → 매일 새로운 기업이 시장에 진입합니다. 이를 수동으로 넣을 순 없기에 매일 실행되는 스케줄러를 도입했습니다.
  2. "스팩(SPAC)은 분석에 방해되는데?" → 기업 합병이 목적인 스팩주들이 섞여 들어오면 데이터 분석 노이즈가 발생합니다. 종목명과 코드를 체크해 스팩 정보는 저장 단계에서 제외했습니다.
  3. "상장 폐지나 관리 종목은 어떡하지?" → 사라지는 종목을 추적하고, 리스크가 있는 종목을 구분하기 위해 **관리 종목 여부(mangIssuYn)와 업데이트 로직(Upsert)**을 추가했습니다.

🏛️ 아키텍처(책임 분리) — 설계 의도와 코드 구현

이 시스템은 단일 책임 원칙(SRP)에 따라 네 가지 주요 레이어로 분리되어 있습니다.

1. 스케줄러 (StockMstScheduler.java)

역할: 정해진 시각에 배치를 실행하는 '트리거'입니다.

설계 의도: 개장 전과 장 마감 후에 데이터를 갱신하여 시스템이 항상 최신 시장 상태를 유지하게 합니다.

Java
 
@RequiredArgsConstructor
@Component
public class StockMstScheduler {
    private final StockMstDownloadService stockMstDownloadService;

    @Scheduled(cron = "0 0 9 * * *")    // 개장 전: 신규 상장 및 관리 종목 반영
    public void updateBeforeMarketOpen() {
        stockMstDownloadService.downloadAndUpdateKospi();
        stockMstDownloadService.downloadAndUpdateKosdaq();
    }

    @Scheduled(cron = "0 0 16 * * *")   // 장 마감 후: 최종 데이터 동기화
    public void updateAfterMarketClose() {
        stockMstDownloadService.downloadAndUpdateKospi();
    }
}

2. 도메인 서비스 (StockMstDownloadService.java)

역할: 파일 다운로드부터 필터링, DB 저장까지 전체 워크플로우를 지휘합니다.

설계 의도: 스팩주 제외 등 비즈니스 규칙을 적용하고, 데이터의 원자성을 보장합니다.

Java
 
@Service
@Transactional
public class StockMstDownloadService {

    @Transactional
    private int updateStocksFromMst(File mstFile, String market) throws Exception {
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(
                new FileInputStream(mstFile), Charset.forName("EUC-KR")))) {
            
            String line;
            while ((line = reader.readLine()) != null) {
                StockMstDto dto = StockMstDto.parseLine(line);
                
                // 1. 필터링: 주식(ST)이 아니거나 스팩(SPAC) 종목인 경우 제외
                if (dto == null || !"ST".equals(dto.getScrtGrpClsCode().trim())
                        || dto.getHtsKorIsnm().contains("스팩")) continue;

                // 2. Upsert 로직: 신규 상장은 Insert, 기존 종목은 정보(관리종목 여부 등) Update
                var existing = stockMapper.selectStockByCode(dto.getMkscShrnIscd());
                if (existing == null) {
                    stockMapper.insertStock(convertDtoToEntity(dto));
                } else {
                    // 관리종목 여부 등 최신 상태 업데이트
                    stockMapper.updateStockBasicInfo(convertDtoToEntity(dto));
                }
            }
        }
    }
}

3. 파서 DTO (StockMstDto.java)

역할: 고정폭(Fixed-length) 바이너리 형식의 MST 파일을 객체화합니다.

설계 의도: 한글이 포함된 데이터이므로 바이트 오프셋을 직접 계산하여 데이터 깨짐을 방지합니다.

Java
 
public class StockMstDto {
    public static StockMstDto parseLine(String line) {
        byte[] b = line.getBytes(Charset.forName("EUC-KR"));
        if (b.length < 280) return null;

        StockMstDto dto = new StockMstDto();
        dto.mkscShrnIscd = byteSub(b, 0, 9);    // 종목코드
        dto.htsKorIsnm   = byteSub(b, 21, 40);  // 종목명
        dto.mangIssuYn   = byteSub(b, 77, 1);   // 관리종목 여부 (중요!)
        
        return dto;
    }
}

4. 영속 계층 (MyBatis Mapper)

역할: DB 테이블 매핑 및 SQL 실행을 담당합니다.

XML
 
<insert id="insertStock" parameterType="Stock">
    INSERT INTO stocks (name, stock_code, std_code, market_type, is_managed)
    VALUES (#{name}, #{stockCode}, #{stdCode}, #{marketType}, #{isManaged})
</insert>

🛠️ 운영 가이드라인 및 레슨런(Lesson Learned)

  • 변화에 대응하기: 시장 데이터는 고정적이지 않습니다. 상장/폐지/관리종목 지정 등의 이벤트를 코드로 자동화하는 것이 운영 공수를 줄이는 핵심입니다.
  • 데이터 정제(Cleaning): 분석 목적에 맞지 않는 스팩주 같은 데이터는 수집 단계에서 미리 걷어내는 것이 DB 건강에 좋습니다.
  • 안정성: MST 파일 오프셋은 증권사 사정에 따라 변할 수 있으므로, 로그 모니터링을 통해 파싱 에러를 즉시 감지해야 합니다.
저작자표시 비영리 변경금지 (새창열림)

'Archive(완료된 내용) > 포트폴리오 강화' 카테고리의 다른 글

[stock101] pdf 업로드 및 추출 -5일차  (0) 2026.01.26
[stock101] dart연동 및 ksi 연동 그리고 리팩토링 -4일차  (1) 2026.01.22
[stock101] LOCK을 누가 계속 잡는 문제.  (0) 2026.01.21
[stock101] KIS API연동 웹소켓 - 2일차  (1) 2026.01.20
[stock101] pdf파일 업로드 및 AI 셋팅 - 1일차  (0) 2026.01.19
'Archive(완료된 내용)/포트폴리오 강화' 카테고리의 다른 글
  • [stock101] pdf 업로드 및 추출 -5일차
  • [stock101] dart연동 및 ksi 연동 그리고 리팩토링 -4일차
  • [stock101] LOCK을 누가 계속 잡는 문제.
  • [stock101] KIS API연동 웹소켓 - 2일차
오늘은치킨이닭
오늘은치킨이닭
개발로 세상을 밝히자.(억지 맞음)
  • 오늘은치킨이닭
    개발세밝
    오늘은치킨이닭
  • 전체
    오늘
    어제
    • 분류 전체보기 (80)
      • Project(마감 기한이 정해진 목표) (2)
        • Docker(도커) (1)
        • Django(장고) (0)
        • 부트캠프 (1)
      • Archive(완료된 내용) (59)
        • 재취업준비 (8)
        • 포트폴리오 강화 (24)
        • 부트캠프 (3)
        • 팁 (2)
        • 데이터베이스 (2)
        • SQL (12)
        • 백엔드 (5)
        • 프론트엔드 (1)
        • 유니티(Unity) (2)
      • Area(일생동안 지속 유지하는 활동,마감X) (16)
        • 게임 (2)
        • 코딩테스트 (12)
        • 운영체제 (0)
        • DB (2)
      • Resource(지속적 관심을 갖는 주제분야) (1)
        • 애니메이션 (0)
        • 내가 선정한 맛집 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    유니티 #설치 #방법 #다운
    맛집
    명동교자
    칼국수맛집
    고클린 #cpu온도보는법 #cpu온도
    롤 #룬 #자동적용 #블리츠 #다운로드 #도움 #TIP #브론즈 #아이언 #브실골 #아브실
    인포그래픽 #자기소개서 #자기소개 #명함삭제
    명동
    DB #데이터베이스
    명동맛집
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
오늘은치킨이닭
[stock101] KIS 코스피 코스닥 종목 정보 매일 최신화하기 - 3일차
상단으로

티스토리툴바