3. 튜토리얼/금융 분석 프로그래밍 응용

파이썬 이더리움 가격 예측 - 회귀모형

swsong 2023. 1. 9. 07:00

많은 딥러닝 입문 도서, 유튜브 콘텐츠 등에서 주가 예측을 소재로 삼고 있다. 자극적이고, 흥미로울 뿐 아니라 예측 결과는 경이로울 정도로 정확해 보여서 주식에 관심 있는 많은 사람들의 관심을 받게 된다.

다음과 같이 'AI가 예측한 주가'라고 하는 시뮬레이션 결과를 보신 적이 있지 않은가?

위 결과는 실제로 모델을 학습시켜 예측한 결과물이며, 심지어 복잡한 딥러닝이 아닌 기본적인 단순 통계모델인 회귀 모형을 사용했다.

딥러닝을 잠깐 접해본 분들은 이 그래프를 보고 '에이, over-fitting 됐네'라거나, '미래 데이터를 학습에 사용했네'라고 지적할 수 있다. 하지만 해당 모델은 over-fitting이 생길 만큼 복잡한 모델을 쓰거나 loss를 과하게 줄이지 않았으며(단순 회귀모형 사용), 위에 보이는 기간은 학습용으로 사용하지 않은, 모델이 처음 보는 데이터를 사용했다.

그럼, 어떻게 저런 결과가 나올 수 있었을까? 

지금부터 회귀모형으로 이더리움 가격을 예측하는 모형을 만들어보고, 해석상 유의해야 할 점을 알아보자.

Step 1. Intro

시계열 데이터에는 '추세'라는 것이 있다. 매매 기술을 관심 있게 찾아본 적이 있다면, '추세 추종'같은 기법을 들어본 적이 있을 것이다. 시계열 데이터는 '예측 가능한 영역'과 '(주어진 데이터로는) 예측 불가능한 영역'으로 나뉜다. 추세나 계절성 같은 것들이 바로 '예측 가능한 영역'에 속하고, 그런 것들을 모두 제거하고 남은 것이 '예측 불가능한 영역'이 된다. 예측 불가능하다는 것은 이론적으로 그것을 맞힐 확률이 50%에 수렴한다는 것을 의미한다.

주가 데이터는 매우 강한 추세를 가지고 있다. 특히 분 단위, 초 단위로 갈수록 주가의 움직임은 무작위성을 띠는 반면 장기적으로 갈수록 그러한 추세는 점점 강해진다. 단순 회귀분석이든 복잡한 딥러닝 신경망이든 결국은 데이터 간 관계를 찾아서 그다음 데이터를 예측하는 원리다. 추세는 주가 데이터의 움직임에 가장 강한 연관성을 담고 있는 핵심 Factor이기 때문에 어떤 모델이든 이 추세를 처리하지 않고 학습시키면 가장 먼저, 그리고 가장 강하게 추세를 학습하게 된다.

주가에 추세가 있다는 것은 어제와 오늘, 오늘과 내일 가격에 서로 강한 관련성이 있음을 의미하고 이를 표현하는 용어가 바로 자기 상관성의 개념이다. 따라서 '주가를 잘 예측'하는 모델은 '추세를 잘 학습한' 모델이 되고, 예측 성능이 매우 뛰어난 모델은 '오늘의 가격'을 '어제의 가격'으로 예측하게 된다.

Step 2. 모델 학습

그럼, 지금부터 위에서 '추세를 잘 추종하는' 회귀 모형을 만들어보자.

2-1. 데이터 불러오기

데이터는 보유하고 있는 이더리움 가격 정보를 가져왔다. 실습을 원하시는 경우 어떤 데이터를 가져와도 상관없으니 네이버나 야후파이낸스 등 다른 사이트를 통해 직접 분석하고 싶은 데이터를 먼저 확보해 보시면 좋겠다.

인덱스가 역순으로 정렬되어 있으니 과거부터 현재순으로 재정렬해 주자.

2-2. 학습 및 평가 데이터 생성

먼저, window 데이터 셋을 생성해 준다. 단일 데이터로 예측 분석을 수행한다는 것은 과거 며칠의 데이터를 보고 다음날의 데이터를 예측할 것인가? 의 문제를 푸는 것이다. 여기서 '과거 며칠'에 해당하는 것이 window size다. 이 window size에 따라서 1일부터 30일까지의 데이터를 보고 31일째 가격을 예측하고, 2일부터 32일까지의 데이터를 보고 32일째 가격을 예측하는 식이다. 이제 이 예측값과 실제 값을 비교해 보면서 모델을 업데이트하는 것이 모델 학습 원리가 된다. 따라서 모델이 학습할 수 있도록 데이터를 window 구간별로 잘라서 맞춰줘야 하는데, '1일부터 30일까지, 2일부터 31일까지, ... , ' 이렇게 겹쳐가며 데이터 셋을 만들어주면 되겠다.

하나의 윈도우가 X(과거 30일 치) 라면 예측하고자 하는 다음날 하루는 y다. 따라서 하나의 학습 시퀀스 사이즈는 예측하고자 하는 하루와 과거 30일(윈도우 사이즈)을 합친 31일이 되고, 이러한 조합으로 데이터 셋을 구성하는 코드는 다음과 같다.

이제 이렇게 구성한 데이터 셋을 학습 데이터, 검증 데이터, 평가 데이터 셋으로 나눠준다. 학습 데이터로는 모델을 적합시키고, 검증 데이터는 학습 과정에서 모델의 예측도를 평가하며 모델을 잘 적합시킬 수 있도록 기준이 되어주고, 평가 데이터 셋으로 모델 성능을 실제 평가하게 된다. 여기서는 학습 데이터 비중을 80%, 검증 및 평가 데이터 비중을 10%씩 확보했다. (여기서는 성능을 높이지 않고 단순히 학습 데이터로 적합하는 것만으로도 겉보기에 매우 성능이 높아 보일 수 있다는 것을 보여드리기 위해 검증 과정을 생략한다.)

2-3. 모델 적합

회귀 모형은 sklearn의 LinearRegression() 함수로 사용할 수 있다. 간단하게 학습 데이터만으로 모델을 적합시킨다.

이제 test 데이터 셋에 대해 평가를 진행하고, 오차 수준을 확인한다. 오차는 mean squared 방식을 사용한다.

이제 예측 결과를 실제 가격 데이터와 놓고 비교해 본다.

어떤가? 매우 잘 예측한 것처럼 보이지 않은가?

그러나 예측 결과 일부를 자세히 보면 마치 예측 가격(파란색)이 실제 가격(초록색)을 복사하는 것처럼 전날의 움직임을 따라가고 있다. 지금은 예측 성능이 높지 않은 아주 간단한 모델이라 이 정도지만, 만약 딥러닝으로 다양한 시점의 다양한 주가를 반복학습을 시켜 데이터에 '적합'하는 과정(오차를 줄이고 예측 성능을 높이는 과정)을 길게 가져갈수록 이 경향은 점점 더 뚜렷하게 나타날 것이다.

Step 3. 모델 평가

두 그래프를 함께 그려놓고 보면 그렇게 보일 수밖에 없다. 오늘의 주가가 떨어졌지만 올랐다고 예측했더라도 전체적으로 놓고 보면 두 차이가 크지 않기 때문에 계속해서 두 선이 겹치며 그려지게 되기 때문이다.

지금부터, 모델의 예측 값이 하루 단위로는 완전히 잘못되더라도 장기적으로는 실제 값을 따라 움직이게 되는 모습을 하루 간격의 예측치로 그려가며 확인해 보겠다.

위 그림은 지난 30일 치 가격으로 31일째 되는 날 가격을 예측하는 순간을 포착한 그래프다. 붉은 점선은 과거 30일 치 중 30일째(관측 대상인 x=1 기준으로 어제)를 기준선으로 표시해 주고 있다.

우리는 x=1을 예측하기 전까지는 실제 값만 가지고 있었지만, x=1부터는 실제 값과 예측값을 가지고 있다. 그리고 실제 값과 예측값은 다소 차이가 있다. 그럼, x=2부터는 어떤 데이터로 예측하게 될까? 시중에 유통되는 정말 많은 도서와 튜토리얼에서는 실제 값을 사용한다. 이것을 두고 '미래 데이터를 입력값으로 사용한 오류'라고 지적하는 경우도 가끔 볼 수 있는데, 엄밀히 말하면 그렇지는 않다. x=2 시점에서는 x=1이 과거가 되기 때문이다.

미래 데이터를 입력값으로 사용하는 흔한 사례는 백테스팅에서 볼 수 있다. 예측하고자 하는 시점에 아직 발표되지 않은 공시 데이터나 해당 시점이 속한 분기의 per을 사용하는 케이스다. 매우 뛰어난 예측 성능을 보여주지만 현실에서 사용할 수 없다.

이와 달리 현재의 예측 방식은 "내가 내일 주가를 예측하고 싶은데, 어제 주가를 예측했지만 조금 빗나갔어. 어제의 실제 주가를 다시 사용해서 내일 주가를 예측해 봐야겠어"와 같이 접근한다. 따라서 관측 시점을 기준으로는 언제나 과거 데이터를 사용하며 이 로직에 오류가 있다고 보기는 어렵다. 다만, 이 결과를 잘못 해석하고 잘못 받아들일 여지는 있다.

전날의 실제 값을 가지고 반복해서 예측하면 어떤 그래프가 만들어지는지 이어서 확인해 보자. 붉은 점선 뒤로는 지난 30일 치 데이터가 있고, 해당 데이터를 사용해 다음날 주가, 그다음 날의 주가를 예측해 나간다.

각 시점(x=2, x=2)에서 실제 값과 예측값은 꽤 큰 차이가 있다. 그렇게 반복하다 보면 우연히 일치하는 구간(x=3)도 나타날 수 있지만 항상 그렇지는 않을 것이다.

이렇게 계속 '전날의 실제 값'을 가지고 예측을 해나가다 보면 장기적으로는 같은 방향으로 그래프가 그려질 수밖에 없다. 각 시점(x)에서는 방향이 엇갈리더라도 그다음 날을 예측할 때에는 실제 값으로 조정된 과거 30일 치를 사용하기 때문에 멀리서 보면 "귀신같이 주가를 맞히는 것처럼" 보인다.

예를 들어보자. 과거 5일 치 테슬라 종가가 100만 원, 200만 원, 300만 원, 400만 원, 500만 원이었다면 6일째 되는 날의 가격은 대부분의 모델(가격만 학습한 경우)이 600만 원이라고 예측할 것이다. 하지만 어떤 외부 요인에 의해 주가가 떨어져서 450만 원이 되었다고 하면 내일의 테슬라 가격은 오늘 예측한 600만 원을 포함해 지난 5일 치 가격 데이터인 200만 원, 300만 원, 400만 원, 500만 원, 600만 원을 가지고 예측하는 것이 아니라 오늘의 실제 가격인 450만 원을 포함해 200만 원, 300만 원, 400만 원, 500만 원, 450만 원을 가지고 예측한다.

모델의 목적이 오늘 가격을 맞히는 것이라면 과거의 실제 값들을 가지고 예측하는 이러한 방식이 것이 잘못된 설계라 보기는 어렵다. 하지만 모델이 마치 지난 30일 치를 보고 다음 30일 치를 연이어 맞히는 것처럼 보여준다면 해석에 오류가 있다고 할 수 있다. 그래프 두 개를 놓고 "귀신같이 맞힌다"라고 결론을 내게 되는 것이 그러한 예시가 된다.

이것이 학습자 입장에서는 과정과 결과를 그대로 받아들이고, 실제 투자까지 이어질 수 있기 때문에 꽤나 위험한 일일 수 있다고 생각한다. 따라서 지난 며칠을 가지고 다음 며칠을 예측하는 모델인지 확인하고, 하루치 예측이라면 타깃 지점인 하루에 대한 결과만 놓고 해석하는 것이 바람직하겠다.