이번 포스트에서는 yfinance를 이용해서 주가 데이터를 직접 수집하는 방법을 다룹니다.
들어가며
그동안 포트폴리오는 구글 스프레드시트로 관리해왔는데, 일부 종목은 가격 데이터가 누락되거나 업데이트가 늦어 전체 포트폴리오를 일관된 기준으로 관리하기 어렵다는 문제가 있었다.
이 문제를 해결하기 위해, 외부 도구에 의존하기보다는 주가 데이터를 직접 수집하고 관리하는 방식을 시도해보기로 했다. 이번 글에서는 "일단 가장 간단한 형태"로, 주가 데이터를 직접 수집하고 1/3/6/12개월 수익률을 계산하는 스크립트를 만들어본다.
주가 데이터 수집 방식 선택
주가 데이터를 수집하는 방법은 다양하다. 가장 대표적인 방법은 증권사 API를 사용하는 것인데, 안정성과 정확성 면에서는 장점이 있다. 다만, 인증 절차, 초기 설정 등 진입 비용이 비교적 큰 편이다.
우선 초기 단계인만큼 빠르게 실험하고 전체 흐름을 파악하는 것이 더 중요하기 때문에 Yahoo Finance 데이터를 SDK 형태로 제공하는 yfinance를 사용하기로 했다. 별도의 인증 없이도 원하는 기간의 데이터를 쉽게 가져올 수 있고, Pandas 기반 분석도 간편하다는 점에서 프로토타이핑 하는 데 가장 적합한 선택이라고 판단했다.
스크립트 구성: "데이터 수집 -> 수익률 계산 -> 결과 출력"
스크립트는 다음 세 단계로 구성되어 있다.
- fetch_price_data: 지정한 기간의 가격 데이터 수집
- calculate_returns: 종가(Close) 기준으로 기간 수익률 계산
- main: 실행 흐름 및 출력
yfinance로 1년치 데이터 수집
yfinance에서는 종목 코드(ticker)와 조회 기간을 지정하는 방식으로 데이터를 가져올 수 있다. 종목 코드는 네이버 증권에서 종목명을 검색하면 확인할 수 있고, 삼성전자의 종목 코드는 "005930"이다. 이를 yfinance에서 사용할 때는 한국거래소를 나타내는 ".KS"를 붙여야 한다.
df = yf.download("005930.KS", start="2025-01-01", end="2026-01-01")

수집된 데이터는 날짜를 인덱스로 하며, 시가(Open), 고가(High), 저가(Low), 종가(Close), 거래량(Volume) 등이 포함된다.
Price Close High Low Open Volume
Ticker 005930.KS 005930.KS 005930.KS 005930.KS 005930.KS
Date
2025-01-02 52272.527344 52468.304600 51195.752436 51587.306948 16630538
2025-01-03 53251.414062 53936.634464 51685.196002 51685.196002 19318046
2025-01-06 54719.746094 55013.411994 53153.527959 53251.416592 19034284
2025-01-07 54230.304688 56090.188783 54230.304688 55600.745600 17030235
2025-01-08 56090.187500 56285.964769 53545.083006 53642.971640 26593553
기간 수익률 계산에서 중요한 포인트: "정확히 n개월 전 데이터는 없을 수 있다"
수익률 계산식 자체는 간단하다.
(현재 가격 / 과거 가격) - 1
하지만 실제 주가 데이터를 다루다 보면, 이 "과거 가격"을 정확히 찾는 것이 생각보다 까다롭다. 대표적인 이유는 다음과 같다.
1) 주말이나 공휴일로 거래가 없다
2) 신규 상장 종목이라면 특정 시점 이전 데이터가 존재하지 않을 수 있다.
즉, "정확히 N개월 전" 날짜의 주가 데이터가 없을 수 있다는 것이다. 이번 포스트에서는 삼성전자를 대상으로 하기 때문에 상장일 문제는 제외하고, 휴장일 문제만 고려해보자.
예제 데이터
import pandas as pd
data = {
"Close": {
"2026-01-01": 101,
"2026-01-02": 102,
# 2026-01-03: 없음 (휴일)
"2026-01-06": 106,
"2026-02-03": 203,
}
}
df = pd.DataFrame(data)
df.index = pd.to_datetime(df.index)
수익률을 계산하기 위해 "2026-02-03"의 1개월 전 가격, 즉 "2026-01-03" 가격을 조회한다고 하자. 이때 .loc[]으로 접근하면 다음과 같이 KeyError가 발생한다.
past_price = df["Close"].loc["2026-01-03"]
# → KeyError: '2026-01-03'
이럴 때 .asof()를 사용하면 지정한 날짜 이전 중 가장 가까운 날짜의 값을 반환해준다. 이 기능 덕분에 휴일, 주말 등으로 인한 결측에도 에러 없이 수익률을 계산할 수 있다.
past_price = df["Close"].asof("2026-01-03")
print(past_price) # 출력: 102.0 (2026-01-02의 종가)
최종 코드
import pandas as pd
import yfinance as yf
def fetch_price_data(ticker, start_date, end_date):
return yf.download(tickers=ticker, start=start_date, end=end_date)
def calculate_returns(df, periods):
close = df["Close"]
latest_date = close.index.max()
latest_price = close.loc[latest_date]
earliest_date = close.dropna().index.min()
returns = {}
for label, offset in periods.items():
past_date = latest_date - offset
if past_date < earliest_date:
returns[label] = float("nan")
continue
past_price = close.asof(past_date)
returns[label] = (latest_price / past_price - 1) * 100
return pd.DataFrame(returns)
def main():
ticker = "005930.KS"
start_date = "2025-01-01"
end_date = "2026-02-03"
periods = {
"1m": pd.DateOffset(months=1),
"3m": pd.DateOffset(months=3),
"6m": pd.DateOffset(months=6),
"12m": pd.DateOffset(months=12),
}
df = fetch_price_data(ticker, start_date, end_date)
returns_df = calculate_returns(df, periods)
print("\n📈 Period Returns (%)")
print("-" * 30)
print(returns_df.round(2).to_string())
print("-" * 30)
if __name__ == "__main__":
main()
실행 결과
📈 Period Returns (%)
------------------------------
1m 3m 6m 12m
Ticker
005930.KS 17.04 40.59 120.33 193.21
------------------------------
나가며
이번 포스트에서는 yfinance를 이용해 주가 데이터를 수집하고, 기간별 수익률을 계산하는 흐름을 살펴보았다. 다음 포스트에서는 이 스크립트를 기반으로, 여러 종목에 대한 수익률을 한번에 계산하고 비교할 수 있는 구조로 확장해볼 예정이다.
'Data' 카테고리의 다른 글
| [Data] Data Engineering Zoomcamp 2주차 (0) | 2026.02.03 |
|---|---|
| [Data] Data Engineering Zoomcamp 1주차 (0) | 2026.01.27 |
| [Data] DE #100일챌린지 - Day 0: 시작 (0) | 2025.10.31 |