동적 자산 배분 포트폴리오를 구성하기 위해 미국 주식(S&P 500 ETF), 한국 거시 경제 지표, 그리고 비트코인(BTC) 데이터를 하나의 판다스(Pandas) 데이터프레임으로 병합(Merge)하는 작업을 진행하고 있었습니다. 그런데 분명히 존재하는 데이터임에도 불구하고 pd.concat이나 pd.merge를 수행한 직후 결과 데이터프레임의 절반 이상이 NaN(결측치)으로 날아가는 기이한 현상이 발생했습니다.
일부 구간에서는 아예 파이썬이 ValueError: Cannot compare tz-naive and tz-aware datetime-like objects라는 붉은 에러를 뱉으며 스크립트를 멈춰버렸습니다. 오늘은 글로벌 금융 데이터를 다룰 때 100% 마주치게 되는 시계열 데이터의 타임존(Timezone) 충돌 원인과 표준화 해결 방법을 정리합니다.
🚨 문제 상황: 각기 다른 시간대의 혼종 (EST, KST, UTC)
에러의 원인은 제가 수집한 각 데이터 소스의 시간 기준(Timezone)이 완전히 중구난방이었기 때문입니다.
- 미국 주식 데이터 (Yahoo Finance): 미 동부 시간(EST/EDT) 기준. 게다가 서머타임(Daylight Saving Time)이 적용되어 여름과 겨울의 장 시작/마감 시간이 UTC 기준으로 달라짐.
- 비트코인 데이터 (Binance API): 24시간 연중무휴로 거래되며, 협정 세계시(UTC) 기준.
- 한국 매크로 지표 (한국은행 Open API): 한국 표준시(KST, UTC+9) 기준. 심지어 시간 정보 없이 ‘날짜(YYYY-MM-DD)’만 덜렁(tz-naive) 있는 경우도 많음.
Pandas는 인덱스(Index)를 기준으로 데이터를 병합하는데, 하나는 타임존 정보가 아예 없는 상태(tz-naive)이고 다른 하나는 타임존 정보가 포함된 상태(tz-aware)이다 보니 서로 비교를 하지 못해 에러가 터지거나 날짜가 어긋나 결측치가 대량 발생한 것입니다.
🛠️ 해결 과정: 모든 시계열의 ‘UTC 표준화’
이 문제를 해결하는 유일하고 가장 깔끔한 방법은 수집한 모든 데이터의 시간을 즉시 ‘UTC(협정 세계시)’로 강제 변환하여 통일하는 것입니다. 데이터베이스에 적재하거나 백테스트 엔진에 태우기 전, 반드시 전처리 파이프라인에서 타임존을 일치시켜야 합니다.
Python
import pandas as pd
import pytz
# 1. 타임존 정보가 없는(tz-naive) 데이터에 타임존 부여하기 (예: 한국 데이터)
# 처음부터 시간 정보가 없었다면 '이 데이터는 KST 기준이다'라고 먼저 명시(localize)해야 합니다.
df_kr.index = df_kr.index.tz_localize('Asia/Seoul')
# 2. 모든 데이터를 UTC로 통일 변환 (tz_convert)
df_kr_utc = df_kr.index.tz_convert('UTC')
# 3. 만약 미국 주식 데이터처럼 이미 타임존이 섞여서 꼬여있는 경우 (EST/EDT)
# 먼저 타임존 정보를 강제로 날려버린 뒤(tz_localize(None)),
# 올바른 타임존을 다시 부여하고 UTC로 변환하는 방식을 씁니다.
df_us.index = pd.to_datetime(df_us.index, utc=True)
# 4. 병합 (Merge)
# 이제 모든 데이터프레임의 인덱스가 tz-aware (UTC) 상태이므로 완벽하게 병합됩니다.
merged_df = pd.merge(df_kr, df_us, left_index=True, right_index=True, how='inner')
추가로, 일봉(Daily) 데이터로 백테스트를 진행할 때는 장 마감 시간의 차이(미국장의 마감이 한국장 다음 날 새벽)로 인해 ‘하루(1 Day)’의 기준이 어긋날 수 있습니다. 이 경우 UTC 변환 후 .dt.date나 .normalize()를 사용하여 시간 단위(시, 분, 초)를 잘라내고 순수 ‘날짜’ 기준으로 리샘플링(Resampling)하는 과정을 거쳐야 데이터 누수를 막을 수 있습니다.
💡 실무 인사이트
퀀트 파이프라인을 구축할 때 ‘시간’은 생각보다 훨씬 더 교묘한 함정입니다. 특히 서머타임(DST)은 백테스트 로직을 소리 없이 망가뜨리는 주범입니다. 데이터 수집(Crawling/API) 모듈을 설계하실 때는 “외부에서 가져온 데이터는 메모리에 올라오는 즉시 UTC로 변환한다”는 대원칙을 세우시길 바랍니다. 화면에 KST로 보여주는 것은 가장 마지막 프론트엔드나 출력 단계에서만 수행해도 충분합니다.