무료로 코인 시세 데이터 수집하는 방법 — 공개 API 활용 가이드
코인 봇을 만들려면 제일 먼저 필요한 건 전략이 아니라 데이터입니다. 다행히 대부분의 거래소는 시세 조회를 무료로, 회원가입이나 API 키 없이 열어 둡니다. 이 글은 그 공개 API로 데이터를 모아 CSV까지 만드는 과정을 다룹니다.
⚠️ 이 글은 교육·정보 제공 목적입니다. 암호화폐는 변동성이 매우 큽니다. 투자 권유가 아니며, 손실 책임은 본인에게 있습니다.
1. 키가 필요한 것과 필요 없는 것
거래소 API는 성격이 둘로 나뉩니다. 이 구분만 알아도 절반은 정리됩니다.
- 공개(Public) API — 시세, 캔들, 호가, 체결 내역. 키 불필요. 누구나 호출 가능.
- 인증(Private) API — 잔고 조회, 주문, 출금. 키와 서명이 필요하고 계정에 직접 영향을 줍니다.
데이터 수집·백테스트 단계에서는 공개 API만으로 충분합니다. 연습 단계에서 굳이 키를 만들 이유가 없고, 만들지 않으면 유출될 것도 없습니다.
2. 현재가 받아오기 (업비트)
import requests
def upbit_price(market="KRW-BTC"):
url = "https://api.upbit.com/v1/ticker"
res = requests.get(url, params={"markets": market}, timeout=10)
res.raise_for_status()
d = res.json()[0]
return {
"market": d["market"],
"price": d["trade_price"],
"change": d["signed_change_rate"] * 100, # 전일 대비 %
}
print(upbit_price())
# {'market': 'KRW-BTC', 'price': 95_400_000, 'change': 1.23}
여러 종목을 한 번에 받을 수도 있습니다. 반복문으로 한 개씩 호출하는 것보다 훨씬 빠르고, 호출 제한에도 안전합니다.
markets = "KRW-BTC,KRW-ETH,KRW-XRP"
res = requests.get("https://api.upbit.com/v1/ticker",
params={"markets": markets}, timeout=10)
for d in res.json():
print(d["market"], d["trade_price"])
3. 과거 캔들 받아오기 — 백테스트의 재료
캔들(OHLCV)은 일정 시간 동안의 시가·고가·저가·종가·거래량을 묶은 데이터입니다. 백테스트는 사실상 이 데이터 위에서 돌아갑니다.
def upbit_candles(market="KRW-BTC", unit=60, count=200):
"""unit: 분 단위(1,3,5,15,60,240). count: 최대 200"""
url = f"https://api.upbit.com/v1/candles/minutes/{unit}"
res = requests.get(url, params={"market": market, "count": count},
timeout=10)
res.raise_for_status()
return res.json() # 최신 → 과거 순서로 옵니다
rows = upbit_candles()
print(len(rows), rows[0]["candle_date_time_kst"])
여기서 한 번에 200개라는 제한이 중요합니다. 더 긴 기간이 필요하면 to 파라미터로 "이 시각 이전"을 지정해 가며 뒤로 이어 붙여야 합니다.
import time
def collect_history(market="KRW-BTC", unit=60, pages=5):
all_rows, to = [], None
for _ in range(pages):
params = {"market": market, "count": 200}
if to:
params["to"] = to # 이 시각 이전 데이터 요청
res = requests.get(
f"https://api.upbit.com/v1/candles/minutes/{unit}",
params=params, timeout=10)
res.raise_for_status()
rows = res.json()
if not rows:
break
all_rows += rows
to = rows[-1]["candle_date_time_utc"] # 가장 오래된 캔들 시각
time.sleep(0.2) # 호출 간격 확보 (필수)
return all_rows
time.sleep(0.2)을 빼지 마세요. 대부분의 거래소는 초당 호출 횟수 제한이 있고, 넘기면 429 오류로 차단됩니다. 0.2초는 초당 5회로, 대체로 안전한 수준입니다.
4. 바이낸스 — 해외 시세와 긴 기간
바이낸스 공개 API는 한 번에 1000개까지 주고, 과거 데이터도 넉넉합니다. 응답이 JSON 배열이라 구조가 조금 다릅니다.
def binance_klines(symbol="BTCUSDT", interval="1h", limit=1000):
url = "https://api.binance.com/api/v3/klines"
res = requests.get(url, params={
"symbol": symbol, "interval": interval, "limit": limit,
}, timeout=10)
res.raise_for_status()
# [open_time, open, high, low, close, volume, close_time, ...]
return [{
"time": k[0],
"open": float(k[1]),
"high": float(k[2]),
"low": float(k[3]),
"close": float(k[4]),
"volume": float(k[5]),
} for k in res.json()]
가격이 문자열로 온다는 점에 주의하세요. float()로 바꾸지 않으면 "95400" > "9600" 같은 문자열 비교가 되어 조용히 틀린 결과가 나옵니다.
5. CSV로 저장하기
import pandas as pd
rows = collect_history("KRW-BTC", unit=60, pages=5)
df = pd.DataFrame([{
"date": r["candle_date_time_kst"],
"open": r["opening_price"],
"high": r["high_price"],
"low": r["low_price"],
"close": r["trade_price"],
"volume": r["candle_acc_trade_volume"],
} for r in rows])
df["date"] = pd.to_datetime(df["date"])
df = df.sort_values("date").drop_duplicates("date") # 시간순 + 중복 제거
df.to_csv("btc_1h.csv", index=False, encoding="utf-8-sig")
print(f"{len(df)}개 저장, {df['date'].min()} ~ {df['date'].max()}")
중복 제거는 반드시 넣으세요. 페이지를 이어 받다 보면 경계에서 같은 캔들이 두 번 들어오고, 그대로 두면 백테스트 결과가 왜곡됩니다.
6. 수집할 때 지킬 것
- 호출 간격 지키기 — 429가 뜨면 잠시 쉬고 재시도. 무한 재시도는 차단으로 이어집니다.
- 한 번 받은 건 저장 — 실험할 때마다 다시 받지 말고 로컬 파일을 재사용하세요. 서버에도, 나에게도 이득입니다.
- 타임존 확인 — KST와 UTC가 섞이면 9시간짜리 오차가 조용히 들어옵니다.
- 이용약관 확인 — 공개 API여도 상업적 재배포는 제한되는 경우가 많습니다.
정리
- 시세·캔들은 공개 API로 키 없이 수집 가능
- 여러 종목은 한 번에 묶어서 요청
- 긴 기간은
to로 페이지를 이어 붙이고 sleep 필수 - 바이낸스는 숫자가 문자열 — 형 변환 확인
- 저장 전 정렬 + 중복 제거, 타임존 통일
데이터가 손에 있으면 전략 실험은 그때부터 시작입니다. 반대로 데이터가 지저분하면, 그 위에서 나온 어떤 결과도 믿을 수 없습니다.
댓글
댓글 쓰기