TimesFM을 한국 주식에 적용해 보았다 — 그리고 잘 안 됐다
해봤고, 잘 안 됐다. 무엇을 했고 왜 안 됐는지 정리했다.
I. 문제의식
출발점은 단순한 궁금증이었다. Google Research가 공개한 시계열 foundation model TimesFM (모델 링크)이, 금융 특화 학습 없이도, 한국 주식 시장에서 의미 있는 신호를 낼 수 있을까.
TimesFM은 본질적으로 시계열 예측 모델이다. 따라서 이번 프로젝트는 처음부터 분류 하나만 본 것이 아니라, 미래 수익률 예측 품질, Open 기준 up/down 분류 정확도, 그 신호를 실제로 사용했을 때의 실현 수익률, 세 축을 함께 봤다.
II. 데이터와 과제 정의
한국 주식 일별 OHLCV 패널 데이터를 사용했다. 분할은 다음과 같이 고정했다.
Table 1. 데이터 분할
| 구간 | 기간 |
|---|---|
| Train | 2016-01-01 ~ 2022-12-31 |
| Validation | 2023-01-01 ~ 2023-12-31 |
| Test | 2024-01-01 ~ 2024-12-31 |
예측 horizon은 1거래일과 5거래일이다. 모델 입력은 close-to-close return 단변량 시계열이고, 라벨은 다음과 같이 정의했다.
- 분류 h=1: Opent+1 > Closet
- 분류 h=5: Opent+5 > Closet
- 회귀 h=1: Closet+1 / Closet − 1
- 회귀 h=5: Closet+5 / Closet − 1
패널 데이터이므로 미래값 생성은 반드시 종목별 groupby + shift(-h)로 처리했다. 종목 경계를 무시하면 라벨이 오염된다.
III. 왜 단변량으로 시작했는가
거래량이나 기술적 보조 지표 같은 입력을 처음부터 붙이지 않은 데는 이유가 있다. TimesFM 공개 구현의 가장 자연스러운 경로가 단변량 예측이기도 하고, 초기에 입력을 복잡하게 구성하면 성능 변화가 모델 자체 때문인지 feature engineering 때문인지 분리하기 어렵다. 이번 실험의 성격은 "최대한 단순한 설정에서 TimesFM 자체가 무엇을 하는지 확인한다"에 가까웠다.
IV. Zero-Shot 평가 방법
Fine-tuning 없이 사전학습된 TimesFM_2p5_200M_torch를 그대로 사용했다.
여기서 한 가지 중요한 점이 있다. TimesFM은 원래 수익률 경로를 예측하는 모델이고, 우리가 실제로 관심 있는 것은 future Open vs today Close라는 분류 과제다. 두 가지가 직접 일치하지 않기 때문에, 평가는 세 단계로 나눠서 봤다.
회귀 관점. 모델이 직접 잘하는 문제—미래 close-return 예측—를 먼저 본다. 모델이 수익률 자체를 얼마나 그럴듯하게 예측하는지 확인하는 단계다.
분류 관점. 모델이 예측한 미래 수익률 경로를 누적해 score를 만들고, 그 부호를 up/down 신호로 변환한다. 이 분류 baseline은 Open 라벨을 직접 학습한 결과가 아니라 return forecast → sign 변환 방식의 proxy다.
수익률 관점. 그 신호를 실제로 사용했다고 가정할 때 실현 수익률이 어떤지 본다. pred_up으로 판단된 종목만 매수하거나, 예측 score 기준 10분위로 나눠서 확인했다.
V. Zero-Shot 결과
미래 수익률 예측 품질. 2024 테스트셋 기준, 모델이 close-return을 얼마나 잘 맞히는지를 먼저 봤다.
Table 2. Zero-Shot 회귀 품질
| 과제 | Sign Accuracy | Correlation | MAE |
|---|---|---|---|
| 1거래일 | 0.4915 | +0.018 | 0.0182 |
| 5거래일 | 0.5223 | −0.054 | 0.0458 |
1거래일은 sign accuracy가 49%대로 사실상 무작위에 가깝다. 5거래일은 sign accuracy만 보면 약간 높지만 correlation이 음수다. Zero-shot TimesFM이 close-return 자체를 강하게 맞힌다고 보기 어려운 상태다.
Open 기준 방향성 분류. 같은 테스트셋에서 open 방향성 분류 성능은 다음과 같다.
Table 3. Zero-Shot 분류 성능
| 과제 | Balanced Accuracy | Macro F1 | Up Precision | Up Recall |
|---|---|---|---|---|
| 1거래일 | 0.5243 | 0.5244 | 0.4337 | 0.4258 |
| 5거래일 | 0.5110 | 0.5076 | 0.4702 | 0.3829 |
| 완전 무작위 기준선은 0.5000. 1거래일 기준 confusion matrix: TP=2,397 / TN=5,168 / FP=3,130 / FN=3,232. | ||||
완전 무작위(0.5000)보다는 조금 낫지만 차이가 매우 작다. 모델이 전반적으로 down에 편향되어 있어 up을 잘 잡아내지 못하는 경향이 있다. 경계적인 수준의 신호다.
실현 수익률 관점. 분류 신호를 실제 매수에 사용했다고 가정했을 때 결과다.
Table 4. Zero-Shot 수익률 비교
| 과제 | 전체 평균 수익률 | pred_up 평균 수익률 | pred_up 비중 |
|---|---|---|---|
| 1거래일 | +0.052% | +0.089% | 39.7% |
| 5거래일 | −0.095% | −0.118% | 37.1% |
1거래일은 pred_up 집단의 평균 수익률이 전체 평균보다 약 0.04%p 높다. 아주 약한 선별력이 있다는 해석이 가능하다. 5거래일은 반대다. 전체 평균 수익률이 이미 음수인 구간에서 pred_up 집단이 그보다 더 낮다. 10분위 분석에서도 점수 상위 분위가 하위 분위보다 수익률이 높다는 단조 구조가 나타나지 않는다. Zero-shot 기준으로 5거래일 과제는 실용성이 없다.
VI. Fine-Tuning을 시도한 이유
1거래일에서 아주 약한 신호가 확인됐기 때문에, 미세조정으로 이 신호를 강화할 수 있는지 확인할 필요가 있었다. 다만 여기서도 선택한 방식은 직접 분류 학습이 아니라 forecasting fine-tuning이었다. 구체적으로는 close-to-close return을 입력으로, 미래 close-return을 타깃으로 학습한다. 수익률 예측이 좋아지면 방향성 해석도 자연히 좋아질 수 있다는 기대였다. TimesFM의 원래 구조에는 맞는 선택이었지만, 이 판단이 나중에 한계로 드러난다.
VII. Fine-Tuning 결과
1거래일. 총 다섯 가지 설정을 순서대로 시도했다. Trainable scope를 제한한 light와 point_head부터 시작했다.
Table 5. 1거래일 — Partial Fine-Tuning
| 설정 | Epoch | Sign Acc | Correlation |
|---|---|---|---|
| light | 1 | 0.4812 | 0.000 |
| light | 2 | 0.4787 | −0.014 |
| light | 3 | 0.4879 | −0.005 |
| point_head | 1 | 0.4801 | +0.001 |
| point_head | 2 | 0.4763 | −0.003 |
| point_head | 3 | 0.4840 | +0.005 |
학습 loss는 줄었지만 validation 지표는 거의 변화가 없었다. 그래서 trainable scope를 전체로 늘렸다. 소규모 샘플부터 시작했을 때 epoch 2에서 sign accuracy 0.5137, correlation 0.147로 잠깐 올라가는 구간이 있었다. 희망적으로 보였지만, 데이터 규모를 키우자 재현되지 않았다.
Table 6. 1거래일 — Full Fine-Tuning (소규모 vs. 중간 규모)
| 설정 | Epoch | Sign Acc | Correlation |
|---|---|---|---|
| full / 소규모 | 1 | 0.4863 | +0.091 |
| 2 | 0.5137 | +0.147 | |
| 3 | 0.5059 | +0.120 | |
| full / 중간 규모 (20k) | 1 | 0.4765 | −0.021 |
| 2 | 0.4778 | −0.053 | |
| 3 | 0.4850 | −0.027 | |
| 4 | 0.4840 | −0.022 | |
| 소규모에서 보인 peak은 데이터 규모 확대 시 재현되지 않았다. | |||
소규모에서 보인 개선은 noise였다. 마지막으로 전체 데이터셋에 early stopping (patience=5, 기준: validation sign accuracy)을 걸고 최대 100 epoch까지 학습했다.
Table 7. 1거래일 — Full Fine-Tuning, 전체셋 + Early Stopping
| Epoch | Sign Acc | Correlation |
|---|---|---|
| 1 | 0.4667 | −0.022 |
| 2 | 0.4907 | −0.046 |
| 3 | 0.4871 | −0.018 |
| 4 | 0.4800 | −0.026 |
| 5 | 0.4818 | −0.025 |
| 6 | 0.4723 | −0.026 |
| 7 | 0.4832 | −0.016 |
| Best validation sign accuracy: epoch 2의 0.4907. 이후 5번 연속 개선 없어 epoch 7에서 조기 종료. | ||
이 수치는 zero-shot 분류 성능(balanced accuracy 0.5243)을 전혀 넘지 못한다.
5거래일. Full 전체셋 + early stopping 하나만 시도했다.
Table 8. 5거래일 — Full Fine-Tuning, 전체셋 + Early Stopping
| Epoch | Sign Acc | Correlation |
|---|---|---|
| 1 | 0.5103 | +0.014 |
| 2 | 0.4791 | −0.028 |
| 3 | 0.5016 | +0.001 |
| 4 | 0.5030 | +0.006 |
| 5 | 0.4915 | −0.010 |
| 6 | 0.4983 | −0.011 |
| Epoch 1이 best. 이후 5번 연속 개선 없어 epoch 6에서 조기 종료. | ||
Epoch 1의 결과가 best였고, 이후 회복이 없어 epoch 6에서 종료됐다. 첫 epoch의 결과가 가장 좋다는 것은, 학습 자체가 validation 성능에 기여하지 못했다는 뜻이다.
VIII. 왜 잘 안 됐는가
결과를 보면 단순히 "학습이 더 필요하다"거나 "하이퍼파라미터를 더 조정해야 한다"고 생각하고 싶어지지만, 여러 설정을 바꿔가며 시도한 패턴을 보면 그쪽 방향이 아닌 것 같다.
핵심 문제는 학습 목표와 최종 평가 목표의 불일치다.
Fine-tuning이 학습하는 것은 Closet+h / Closet − 1을 더 잘 예측하는 것이다. 하지만 우리가 실제로 관심 있는 것은 Opent+h > Closet라는 이진 분류다. Close와 Open은 다른 가격이다. Close 수익률 예측을 정교하게 만들어도, 그것이 Open 방향 분류로 자연스럽게 이어지지 않는다.
이 구조 하에서는 학습 loss가 줄어도 우리가 보고 싶은 지표가 개선되지 않을 수 있다. 실제로 그렇게 됐다. 이 문제는 더 많이 학습하거나 설정을 바꾼다고 해결되지 않는다. 타깃 자체를 바꿔야 한다.
IX. 지금까지의 결론
이번 실험에서 정리되는 결론은 다섯 가지다.
첫째, TimesFM zero-shot은 한국 주식에서 아예 무의미한 수준은 아니다. 둘째, 그러나 신호가 매우 약하고, 1거래일에서만 겨우 활용 가능성을 (약하게) 논할 수 있는 수준이다. 셋째, 5거래일은 zero-shot 기준으로도 약했고 수익률 관점에서도 불리했다. 넷째, close-return forecasting → open direction 해석 경로의 fine-tuning은 1거래일과 5거래일 모두에서 안정적인 개선을 만들지 못했다.