IT잡동사니좌충우돌경험기

코딩을 몰라도 괜찮아요 — AI로 코드 만들어 구글 코랩에서 돌리기 (KRX API 2탄)

world1000 2026. 7. 16. 12:41

1탄에서 받은 인증키가 있다면, 이제 코드는 인공지능에게 부탁해 만들고 구글 코랩(브라우저에서 파이썬을 돌리는 무료 도구)에서 실행하면 됩니다. 단, 인증키만은 절대 AI에 넣지 않습니다. 이 한 가지만 지키면 나머지는 어렵지 않습니다.

1탄에서 KRX 인증키를 발급받으셨나요? 그렇다면 코딩을 배우지 않아도 데이터를 받아 볼 수 있습니다. 요즘은 인공지능에게 "이런 코드를 만들어 줘"라고 부탁하고, 그 코드를 구글 코랩에 붙여 실행하는 방식이 흔합니다. 오늘은 그 과정을 초보자 눈높이에서 짚되, 사고 없이 안전하게 쓰는 법에 무게를 두겠습니다.


① 인공지능에게 코드를 부탁하는 법 — 좋은 질문이 좋은 코드를 만듭니다

인공지능은 두루뭉술하게 물으면 두루뭉술하게 답합니다. 네 가지를 또박또박 적어 주면 훨씬 정확해집니다. 무엇을 하고 싶은지(목적), 무엇을 넣을지(입력), 무엇을 받고 싶은지(출력), 그리고 어디서 돌릴지(환경)입니다.

예를 들어 이렇게 부탁하면 좋습니다.

"파이썬 코드를 만들어 줘. KRX 오픈API로 특정 날짜(basDd)의 코스피 지수를 받는 코드야. 호출 주소는 http://data-dbg.krx.co.kr/svc/apis/idx/kospi_dd_trd이고, 요청 헤더에 AUTH_KEY를 넣어. 인증키는 실제 값 대신 여기에_내_키라고 자리표시자로 두고, 결과를 보기 좋게 출력해 줘. 구글 코랩에서 실행할 거야."

여기서 굵게 강조한 부분이 핵심입니다. 실제 키 대신 자리표시자를 넣어 달라고 명시하는 것이죠. 왜 그런지는 뒤에서 다시 말씀드리겠습니다.


② 만든 코드를 구글 코랩에서 실행하기

받은 코드를 실행할 가장 쉬운 곳이 구글 코랩입니다.

구글 코랩(Colab)이 뭐예요? 내 컴퓨터에 아무것도 깔지 않고, 브라우저에서 파이썬을 바로 돌릴 수 있는 구글의 무료 서비스입니다. 코드를 칸(셀)에 붙여 넣고 실행 버튼만 누르면 됩니다.

순서는 이렇습니다. 먼저 colab.research.google.com에 접속해 새 노트북을 만듭니다.

왼쪽 위에 파일을 누르면

Drived의 새 노트북을 클릭하면

코딩을 시작하거나 AI로 코드를 생성하세요.라고 써 있는 부분을 셀이라고 부릅니다. 여기에 코드를 넣으시면 됩니다.
빈 셀에 인공지능이 준 코드를 붙여 넣고, 왼쪽의 실행 버튼(▶)을 누릅니다. 만약 requests 같은 준비물이 없다는 오류가 나오면, 맨 위에 셀을 하나 더 만들어 !pip install requests를 먼저 실행한 뒤 코드를 돌리면 됩니다. 실행이 끝나면 결과가 셀 아래에 그대로 나타납니다.

.ipynb라는 노트북 파일을 이미 갖고 있다면, 코랩에서 '파일 → 노트북 업로드'로 열어 같은 방식으로 실행할 수 있습니다.


③ 오류가 나면 인공지능에게 그대로 물어보세요

처음에는 빨간 오류 메시지가 뜨는 게 자연스럽습니다. 당황하지 말고, 그 오류 메시지를 통째로 복사해 인공지능에게 "이런 오류가 났어. 왜 그럴까? 어떻게 고쳐?"라고 물어보세요. 대개 한두 번 주고받으면 해결됩니다. 이때도 오류 메시지에 혹시 내 키가 섞여 있지 않은지 한 번 훑어보고, 있다면 지운 뒤 붙여넣는 습관을 들이면 좋습니다.

혹시 필요하다면 이 코드를 가져다 코랩 셀에 붙여넣기 하고 위의 제목이 untitled.ipynb로 되어 있을텐데 untitled를 변경하여 파일이름으로 바꾸면 됩니다.

import sys, subprocess, json, getpass
from pathlib import Path

def _ensure(*pkgs):
    for p in pkgs:
        mod = {'koreanize-matplotlib': 'koreanize_matplotlib'}.get(p, p.split('==')[0])
        try:
            __import__(mod)
        except Exception:
            subprocess.run([sys.executable, '-m', 'pip', 'install', '-q', p])
_ensure('requests', 'pandas', 'pykrx', 'koreanize-matplotlib')

import requests
import pandas as pd

AUTH_KEY = getpass.getpass('KRX 오픈API 인증키(AUTH_KEY) 붙여넣기: ').strip()
BAS = input('날짜(YYYYMMDD, 예: 20260715): ').strip()
KRX_ID = input('KRX 아이디(수급 안 받으면 Enter): ').strip()
KRX_PW = getpass.getpass('KRX 비밀번호(수급 안 받으면 Enter): ').strip() if KRX_ID else ''

BASE = 'http://data-dbg.krx.co.kr/svc/apis'
TEXT_COLS = {'BAS_DD','ISU_CD','ISU_NM','MKT_NM','SECT_TP_NM','IDX_CLSS','IDX_NM'}

def get(cat, svc):
    r = requests.get(f'{BASE}/{cat}/{svc}', headers={'AUTH_KEY': AUTH_KEY},
                     params={'basDd': BAS}, timeout=20)
    r.raise_for_status()
    js = r.json()
    rows = js.get('OutBlock_1') or next((v for v in js.values() if isinstance(v, list)), [])
    df = pd.DataFrame(rows)
    for c in df.columns:
        if c not in TEXT_COLS:
            df[c] = pd.to_numeric(df[c].astype(str).str.replace(',', '').replace('', 'nan'), errors='coerce')
    return df

def index_insight(df, main_name):
    if df.empty or 'FLUC_RT' not in df.columns:
        return {'note': '데이터 없음(날짜/승인 확인)'}
    d = df.dropna(subset=['FLUC_RT']).copy()
    if d.empty:
        return {'note': '등락률 비어 있음'}
    rep = d[d['IDX_NM'].str.strip() == main_name]
    head = None
    if len(rep) and pd.notna(rep.iloc[0]['CLSPRC_IDX']):
        head = {'지수': main_name, '종가': float(rep.iloc[0]['CLSPRC_IDX']),
                '등락률(%)': float(rep.iloc[0]['FLUC_RT'])}
    ranked = d.sort_values('FLUC_RT', ascending=False)
    return {'대표지수': head,
            '등락_상위(업종·계열 포함)': ranked.head(6)[['IDX_NM','FLUC_RT']].values.tolist(),
            '등락_하위': ranked.tail(6)[['IDX_NM','FLUC_RT']].values.tolist()}

def stock_insight(df, market):
    if df.empty or 'FLUC_RT' not in df.columns:
        return {'market': market, 'note': '데이터 없음(날짜/승인 확인)'}
    d = df.dropna(subset=['FLUC_RT']).copy()
    if d.empty:
        return {'market': market, 'note': '등락률 비어 있음'}
    up, down, flat = int((d.FLUC_RT>0).sum()), int((d.FLUC_RT<0).sum()), int((d.FLUC_RT==0).sum())
    tot = d['ACC_TRDVAL'].sum(); top = d.nlargest(10, 'ACC_TRDVAL')
    conc = round(100*top['ACC_TRDVAL'].sum()/tot, 1) if tot else None
    return {'market': market, '종목수': int(len(d)),
            '상승': up, '하락': down, '보합': flat, '상승비율(%)': round(100*up/len(d),1),
            '평균등락률(%)': round(float(d.FLUC_RT.mean()),2),
            '거래대금_상위10_집중도(%)': conc,
            '등락률_상위': d.nlargest(10,'FLUC_RT')[['ISU_NM','FLUC_RT']].values.tolist(),
            '등락률_하위': d.nsmallest(10,'FLUC_RT')[['ISU_NM','FLUC_RT']].values.tolist(),
            '거래대금_상위': top[['ISU_NM','ACC_TRDVAL']].values.tolist()}

OUT = Path('krx_data') / f'{BAS[:4]}-{BAS[4:6]}-{BAS[6:]}'
OUT.mkdir(parents=True, exist_ok=True)
summary = {'date': BAS, '지수': {}, '종목': {}, '수급': {}}

if AUTH_KEY:
    for cat, svc, name, main_nm in [('idx','kospi_dd_trd','KOSPI지수','코스피'),
                                    ('idx','kosdaq_dd_trd','KOSDAQ지수','코스닥')]:
        try:
            df = get(cat, svc); print(f'{name}: {len(df)}행')
            df.to_csv(OUT/f'{name}.csv', index=False, encoding='utf-8-sig')
            summary['지수'][name] = index_insight(df, main_nm)
        except Exception as e:
            print(f'{name} 실패: {e}')
    for cat, svc, name in [('sto','stk_bydd_trd','유가증권'),('sto','ksq_bydd_trd','코스닥')]:
        try:
            df = get(cat, svc); print(f'{name} 종목: {len(df)}행')
            df.to_csv(OUT/f'{name}_종목.csv', index=False, encoding='utf-8-sig')
            summary['종목'][name] = stock_insight(df, name)
        except Exception as e:
            print(f'{name} 실패: {e}')
else:
    print('인증키가 없어 오픈API 부분을 건너뜁니다.')

if KRX_ID and KRX_PW:
    import os
    os.environ['KRX_ID'] = KRX_ID; os.environ['KRX_PW'] = KRX_PW
    try:
        from pykrx import stock
        for market in ['KOSPI', 'KOSDAQ']:
            try:
                inv = stock.get_market_trading_value_by_investor(BAS, BAS, market)
                summary['수급'][market] = {k: int(inv.loc[k, '순매수'])
                                           for k in ['외국인','기관합계','개인'] if k in inv.index}
                print(market, '수급:', summary['수급'][market])
            except Exception as e:
                summary['수급'][market] = {'error': str(e)[:150]}; print(market, '수급 실패:', str(e)[:150])
    except Exception as e:
        print('pykrx 실패:', str(e)[:150])
else:
    print('KRX 로그인 미입력 → 수급 단계 건너뜀(수급은 마감 뉴스로 대체).')

(OUT/'_insight_final.json').write_text(json.dumps(summary, ensure_ascii=False, indent=2), encoding='utf-8')
print('\n저장 폴더:', OUT.resolve())
print(json.dumps(summary, ensure_ascii=False, indent=2)[:2500])

try:
    import matplotlib; matplotlib.use('Agg')
    import koreanize_matplotlib  # noqa
    import matplotlib.pyplot as plt
    plt.rcParams['axes.unicode_minus'] = False
    idx_items = [(k, v.get('대표지수')) for k, v in summary['지수'].items() if isinstance(v, dict) and v.get('대표지수')]
    flow = summary['수급'].get('KOSPI', {}) if isinstance(summary['수급'].get('KOSPI'), dict) else {}
    has_flow = any(k in flow for k in ['외국인','기관합계','개인'])
    n = 2 if has_flow else 1
    fig, axes = plt.subplots(1, n, figsize=(6*n, 4.6), squeeze=False); ax = axes[0]
    if idx_items:
        names=[d['지수'] for _,d in idx_items]; vals=[d['등락률(%)'] for _,d in idx_items]
        ax[0].bar(names, vals, color=['#d94141' if v>=0 else '#2f6fb0' for v in vals]); ax[0].axhline(0,color='#888',lw=.8)
        ax[0].set_title(f'대표지수 등락률 ({BAS})'); ax[0].set_ylabel('%')
        for i,v in enumerate(vals): ax[0].text(i, v, f'{v:+.2f}', ha='center')
    if has_flow:
        who=[k for k in ['외국인','기관합계','개인'] if k in flow]; v=[flow[k]/1e8 for k in who]
        ax[1].bar(who, v, color=['#d94141' if x>=0 else '#2f6fb0' for x in v]); ax[1].axhline(0,color='#888',lw=.8)
        ax[1].set_title('유가증권 수급 (억원)')
        for i,x in enumerate(v): ax[1].text(i, x, f'{x:,.0f}', ha='center')
    plt.tight_layout(); plt.savefig(OUT/'chart.png', dpi=130)
    print('차트 저장:', (OUT/'chart.png').resolve())
except Exception as e:
    print('차트 생략:', str(e)[:120])

④ 절대 규칙 — 인증키·비밀번호·개인정보는 AI와 공개된 곳에 넣지 않기

1탄에서 강조한 그 규칙을, 코드를 만들 때 다시 지켜야 합니다. 인공지능 대화창은 편리하지만, 거기에 진짜 인증키를 붙여넣는 순간 그 키는 내 통제를 벗어납니다. 대화가 저장되거나 다른 곳에 남을 수 있기 때문입니다.

그래서 방법은 간단합니다. 코드를 만들 때는 키 자리에 여기에_내_키 같은 자리표시자를 넣어 받고, 코랩에서 실행하기 직전에 그 자리에만 내 진짜 키를 채웁니다. 더 안전하게 하려면 코랩의 '보안 비밀(Secrets)' 기능에 키를 저장해 불러오는 방법도 있습니다. 그리고 그 노트북을 남과 공유하거나 블로그에 올릴 때는, 키를 다시 자리표시자로 바꾼 뒤 공유하세요.

같은 원칙이 증권사 브로커 API(예: 한국투자증권)의 앱키·시크릿에는 더 엄격하게 적용됩니다. 그것은 실제 주문과 계좌까지 닿는 열쇠라, 절대 인공지능 대화창이나 공개 노트북에 넣지 말아야 합니다.


⑤ 가볍게 여기면 생길 수 있는 일

"어차피 나만 보는 노트북인데" 하고 키를 코드에 박아 두었다가, 그 노트북을 무심코 공유하거나 깃허브에 올려 유출되는 경우가 실제로 흔합니다. 유출된 키로 남이 내 한도를 소진하면 계정이 정지될 수 있고, 브로커 키라면 부정 거래와 자산 피해로 이어져 형사 문제로 번질 수 있습니다. 인공지능은 코드를 만들어 주는 좋은 조수이지만, 비밀(키·비밀번호·개인정보)을 맡기는 금고는 아닙니다. 이 선만 분명히 그으면, 나머지는 마음 편히 활용하시면 됩니다.


인공지능과 코랩을 함께 쓰면, 코딩을 몰라도 나만의 데이터 수집 도구를 만들 수 있는 시대입니다. 겁내지 말고 작은 코드부터 시작해 보세요. 다만 키 하나만은 늘 나만 아는 자리에 두시기를 당부드립니다.

참고

이 글은 안전한 사용을 돕기 위한 안내이며, 법률 자문이 아닙니다. 구체적 책임과 이용 범위는 각 서비스의 약관과 관련 법령을 확인하시기 바랍니다.

반응형