인공지능 (AI) 따라잡기

[AI야 놀자] 2편 : KRX OPEN API로 ETF 데이터 뽀개기

MoneyManager 2025. 6. 25. 00:10
728x90

[AI야 놀자] 2편은 chatGPT + 구글시트 + KRX OPEN API를

통해 ETF 관련 데이터와 놀아보겠습니다.    

 

최근 국내 ETF 시장이 200조원을 돌파하면서 관심이 커지고 있습니다. 

 

이번 포스팅의 핵심은 chatGPT로 한국거래소의 OPEN API 에서 제공하고 있는 ETF데이터를 활용하기 위해 코딩을 시키는 것입니다. 

 

한달 요금 22달러인 chatGPT 이용료 본전 뽑아 먹으려고 별걸 다 시키고 있습니다.  ㅎㅎ 

 

일단 결과물을 먼저 설명하고 나서 뒷 부분에 해당 코드 (구글시트 앱 스크립트)와 chatGPT 프롬프트를 넣어 두겠습니다. 


  • 2025년 6월 23일 ETF 전체 data 에서 종목명에 '방산' 이 포함된 종목 추출 하기     


입력 변수는 다음과 같습니다. 

 

A1  시작일  :  20250623

A2  종료일  :  20250623

A3  종목코드 : 

A4  키워드    : 방산

 

조건 입력을 마무리 한 후 실행은 화면상에 있는 엔터키를 클릭

 

 


2025년 6월 1일 ~ 2025년 6월 23일까지 ETF 전체 data 에서 종목코드가 '449450' 인 종목을 일자별로 추출 

 

 

입력 변수는 다음과 같습니다. 

 

A1  시작일  :  20250601

A2  종료일  :  20250623

A3  종목코드 :  '449540   (텍스트로 입력)

A4  키워드    :                  (공백)

 

엔터라고 되어 있는 도형을 클릭하면 6월 1일 부터 6월 23일까지  종목코드 449540인 PLUS K방산 ETF의 일자별 데이터를 추출합니다.   

 

PLUS는 한화자산운용의 ETF 브랜드 명입니다. 

 

참고로, 삼성자산운용은 KODEX, 미래에셋자산운용은 TIGER, 한국투자신탁운용은 ACE 라는 ETF 브랜드를 사용합니다. 


2025년 6월 1일 ~ 2025년 6월 23일까지 ETF 전체 data 추출하기

 

 

A1  시작일  :  20250601

A2  종료일  :  20250623

A3  종목코드 :                  (공백)

A4  키워드    :                  (공백)

 

엔터가 있는 도형을 클릭하니 31.9초 가량 데이터를 주고 받기 하다고 결과를 출력해 줬습니다. 

 

상장 ETF가 900여 종목이 되다 보니 마지막 행은 무려 1만3836행까지 있네요.   


기왕 데이터를 추출 했으니 살짝 응용해 보겠습니다. 

 

1. 피벗테이블을 통해 일자별 ETF 순자산 총액을 집계 합니다. 

2. 그래프를 그리기 위해 순자산 총액을  조원 단위로 변환합니다. 

3.날짜가 현재 텍스트 '20250602' 로 되어 있어서 엑셀과 동일한 구글시트 함수를 사용해 날짜로 변환 해줍니다. 

 

=DATE(value(left(A2,4)),value(mid(A2,5,2)),value(mid(A2,7,2)))

 

4. 일자와 순자산 총액을 기반으로 그래프를 그려 줍니다.  

 

여기서 ETF 순자산 총액인 200조원을 넘어서 여전히 증가세를 보이고 있다는 점입니다. 

필요하면, 자산운용사 별로도 성장세를 분석할 수 있답니다.  

 

현재 국내 ETF 시장은 삼성자산운용(80조원 돌파) , 미래에셋자산운용의 양강 구도 속에 한국투자신탁운용, KB자산운용이 3위 4위를 달리고 있습니다. 

 


 

이제는 chatGPT를 강하게 압박해서 만들어 낸 스크립트 (또는 코드) 를 공개합니다. 

 

아래에 있는 해당 코드에서 인증키 부분은 한국거래소에서 발급받은 인증키로 바꾸시면 됩니다. 
또한, 시트명은 반드시 ETF_시세 로 해주세요. 

 

const authKey = "A1E5XXXXXXXXXXXXXXXXXXXXXFEA5";


 

구글시트 용 앱 스크립트 최종 버전 

 

function fetchETFDataWithPerfectSkip() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('ETF_시세');
  const authKey = "A1E5XXXXXXXXXXXXXXXXXXXXXFEA5";

  const startDate = sheet.getRange("A1").getValue().toString();
  const endDate = sheet.getRange("A2").getValue().toString();
  const filterCode = sheet.getRange("A3").getValue().toString();
  const filterKeyword = sheet.getRange("A4").getValue().toString();

  sheet.getRange("A10:Z20000").clearContent();

  const headers = [
    "기준일자", "종목코드", "종목명", "종가", "대비", "등락률", "순자산가치(NAV)", "시가", "고가", "저가",
    "거래량", "거래대금", "시가총액", "순자산총액", "상장좌수", "기초지수명", "기초지수종가", "기초지수대비", "기초지수등락률"
  ];
  const results = [headers];

  let date = new Date(startDate.replace(/(\d{4})(\d{2})(\d{2})/, '$1-$2-$3'));
  const end = new Date(endDate.replace(/(\d{4})(\d{2})(\d{2})/, '$1-$2-$3'));

  while (date <= end) {
    const ymd = Utilities.formatDate(date, "Asia/Seoul", "yyyyMMdd");
    const day = date.getDay();
    if (day === 0 || day === 6) { // 토, 일 skip
      date.setDate(date.getDate() + 1);
      continue;
    }

    const response = UrlFetchApp.fetch(`${url}?basDd=${ymd}`, {
      method: 'get',
      headers: { "AUTH_KEY": authKey },
      muteHttpExceptions: true
    });

    const json = JSON.parse(response.getContentText());
    const rows = json.OutBlock_1;

    if (!rows || rows.length === 0 || !rows.some(r => r.TDD_CLSPRC && r.TDD_CLSPRC !== "-")) {
      date.setDate(date.getDate() + 1);
      continue;
    }

    rows.forEach(row => {
      const code = row.ISU_CD.toString();  // 텍스트 처리
      const name = row.ISU_NM;

      const codeMatch = filterCode === "" || code === filterCode;
      const nameMatch = filterKeyword === "" || name.includes(filterKeyword);
      const hasClosePrice = row.TDD_CLSPRC && row.TDD_CLSPRC !== "-";

      if (codeMatch && nameMatch && hasClosePrice) {
        results.push([
          row.BAS_DD,
          `'${code}`,  // 종목코드를 강제로 텍스트로 출력
          name,
          row.TDD_CLSPRC,
          row.CMPPREVDD_PRC,
          row.FLUC_RT,
          row.NAV,
          row.TDD_OPNPRC,
          row.TDD_HGPRC,
          row.TDD_LWPRC,
          row.ACC_TRDVOL,
          row.ACC_TRDVAL,
          row.MKTCAP,
          row.INVSTASST_NETASST_TOTAMT,
          row.LIST_SHRS,
          row.IDX_IND_NM,
          row.OBJ_STKPRC_IDX,
          row.CMPPREVDD_IDX,
          row.FLUC_RT_IDX
        ]);
      }
    });

    date.setDate(date.getDate() + 1);
  }

  if (results.length > 1) {
    sheet.getRange(10, 1, results.length, results[0].length).setValues(results);
  } else {
    sheet.getRange("A10").setValue("조건에 맞는 데이터가 없습니다.");
  }
}

 


앱 스크립트를 구글시트에 적용하는 방법

 


 

 

주의 : 처음 스크립트를 작성하고 실행을 하게 되면, 구글 계정에 대한 승인 절차가 있습니다.  이부분은 1편에 설명되어 있으니 참고하시면 되겠습니다. 


 

chatGPT 프롬프트를 첨부합니다.  

아래 내용중에 명령조로 주인행세 하는 것은 접니다. ㅎㅎ

AI에게 호칭을 부장님이라고 학습시켜 놨더니 요즘 MZ 세대와 달리 아주 말을 잘 듣습니다.  

 

 

 

<1번 프롬프트>

한국거래소 KRX OPEN API를 활용해서 ETF 정보를 추출하는 코드를 작성하려고 해.

아래의 6가지 조건을 만족하는 구글시트용 스크립트 코드를 만들어 줘

 

<아래>

 

1. authKey = "A1E5XXXXXXXXXXXXXXXD96FEA5" 사용

2. 종목코드는 텍스트로 처리.

3. 토요일과 일요일은 skip 하고 '종가' 의 데이터가 없으면 공휴일로 간주해서 해당일은 skip 해줘.

4. 'ETF_시세' 시트의 A4:Z20000 까지 클리어 clear 할 것

5. A3 셀에 종목코드 (텍스트) 를 입력받을 것

    if   A3 셀 = "" 이면 지금처럼 전체를 출력

       else A3 셀 = 종목코드 이면 해당 종목만 출력

6. 출력은 A5셀부터 출력할 것

 

 

<1번 프롬프트에 대한 chatGPT 응답>

아래는 부장님께서 요청하신 KRX OPEN API 기반 ETF 일별 시세정보 추출용 구글 Apps Script입니다. 6가지 조건을 모두 반영했습니다.

 

 


 

<2번 프롬프트>

 

아래의 <지침> 사항을 고려해서 A1 셀의 시작일자, A2셀의 종료일자, A3 셀의 코드번호 A4 셀의 '키워드'를 받고 A4셀에 키워드가 입력되어 있으면, 종목명에 '키워드'가 포함 되어 있는 데이터를 모두 출력하도록 스크립트를 작성해 줘.
 
<지침>
1. (A3 = "" and A4 = "") : 전체 출력
2. (A3 셀에 코드번호 입력 & A4 셀 ="") : 코드번호와 매칭 되는 data 출력
3. (A3 = "" & A4 셀에 키워드 입력) : 종목명에 해당 키워드를 포함하는 모든 데이터 출력
4. 출력위치는 기존의 A5 셀부터가 아니고 A10 셀로 조정한다.
5. 기존 데이터 클리어 구간 "A4:Z20000" 을 "A10:Z20000" 정정한다.
 

<2번 프롬프트에 대한 chatGPT 응답>



<3번 프롬프트>

 

아래의 <조건> 으로 응답을 받은 결과 토요일과 일요일의 data 는 skip 성공했다.

 

주중에 휴장일이 있는 경우도 데이터가 공백 상태로 출력 되는 문제점이 있어 해당일에 데이터가 없는 상황이라면 해당일은 skip 하는 것으로 스크립트를 수정해 줘.

 

<예시>

2025년 6월 3일은 평일이지만, 대통령 선거에 따른 휴장, 6월 6일은 공휴일로 휴장함.

 

<조건>

A1셀 : 20250601 A2 셀 : 20250623 A3 셀 : '102110 A4 셀 : ""

 

<3번 프롬프트에 대한 chatGPT 응답>


 

그외 출력 결과물을 보면서 미세하게 조정하면서 마무리 했습니다. 

 

다음은 나머지 프롬프트와 chatGPT와의 응답 내용입니다.    

 





 

 

728x90