2019년 6월 1일 토요일

MLP와 Firm Stock Price

딥러닝을 처음 배우면서 Finance Data에 적용해봐야겠다! 하고 처음 해본 건 아무래도
Simple MLP를 통해 stock price prediction을 해보려고 했던 것 같아요.

여러 Hyperparameter들을 바꿔가면서 조금이라도 유사하게 만들어보려고 시도해봤었어요.

결과적으로는 당연히 실패지만
(성공했으면 올리지 않았겠죠ㅋㅋ 이거 쓰는 대신 수익화할 준비를 하고 있겠죠..ㅠㅠ)
정리하면서 생각해 볼 것도 있고 해서 적어봅니다!

우선 Stock Price는 국내 코스피/코스닥 기업의 일별 종가를 사용했습니다.
데이터 받아오는 건 네이버 금융에서 크롤링해서 받아왔습니다.
사실 매번 크롤링 하는 코드 짜기가 귀찮아서 나름대로는 모듈화를 해놓았는데,
시간이 되면 코드 공부 차원에서 한 번 포스팅해보는 것도 좋겠네요!






get_data_by_name 함수는 그냥 일별 종가를 리스트로 반환하도록 만들어 놓았어요!
받아온 Data는 총 1000개로, 부족할 수 있지만 뭐 의미 있는 결과를 가져올거라고는 생각하지 않아서 그냥 1000개로 해봤어요..ㅋㅋ
(한 페이지에 10개씩 100페이지라서 1000개)

카카오를 예시로서 사용한건 처음 주식을 샀을 때 사본 게 카카오라서...하하
아무튼 단순 Price에서만 뭔가를 뽑아낼 수는 없을까!! 하고 시작해보았습니다.

Data 분할은 Dev Set은 두지 않고, Training Set과 Test Set만 두고 분할했습니다.
Training Set 900개, Test Set 100개로 놓았습니다.

첫 번째 고민은, 과연 Input을 몇 개로 하는 게 적당할까? 였습니다.
이 말은 곧 최근의 며칠 간의 종가를 통해 내일의 종가를 예측하는게 가장 합리적인걸까?
라는 말과 비슷한데요, (물론 차트만 보고 의미있는 값을 찾아내기란 실제로는 불가능할 수도 있지만요) 그나마 가장 효율적인건 몇 개 일까? 입니다.

어떻게 생각해보면 정보량이 많으면 많을수록 조금이라도 도움이 될 수 있지만, 뉴럴넷은 Noise에 취약하기 때문에, 너무 많은 정보를 포함하게 되면 그만큼 Noise가 많이 끼게 되어서 과한 데이터는 오버피팅을 불러올 가능성이 높게 됩니다.

따라서 언제나 그렇듯, 언더피팅과 오버피팅 사이의 적절한 줄다리기는 매우 중요합니다.

물론 Layer수나 Node수에 따라서 다 체크를 해봐야 하기도 하지만, 시간은 소중하니까
Layer수와 Node수는 Input - 64 - 16 - 1로 고정해놓고 Input을 조정하면서 최적을 찾아볼게요! (저렇게 정한 이유는 추후에 적겠습니다.)

최소 2개 ~ 최대 90개로 놓고 돌려봤습니다.
1개일 경우 array dimension이 줄어서 부가로 expand해줘야 할 것 같아서...하하
90개 이상으로 가면 사실 의미가 없을 것 같아서 90개로 했습니다.
거래일 기준으로 90일이니까 4달 살짝 넘지 않을까 싶네요!

training은 full batch로 각각 3000번씩 돌렸습니다. 적절한지는 추후에 확인해보도록 하죠!

데스크탑이 아니라 노트북이라서 돌아가는 시간이 꽤 걸리네요..

training loss와 test loss를 기준으로 비교해보았습니다.
















x축이 input size고, y축이 loss입니다.
loss는 mean square를 사용하였습니다.
코드를 보시면 아실 수도 있겠지만, 놀랍게도 test set loss가 training set loss보다 대체로 낮게 분포해 있습니다.

이유는 짐작컨대 mean square loss를 사용한 것과 data의 분산 문제가 아닐까 싶네요.
아무래도 mean square loss를 사용하게 되면 outlier에 영향을 많이 받으니까, training set에서 예측값과 크게 다르게 한 번이라도 움직이면 아무래도 loss가 커질 테니까요.
이따가 더 자세히 확인해 보도록 하고 우선은 원래 목표에 대해 생각해봅시다.

많은 정보를 가지고 있으면 더 좋게 느껴질 수도 있지만, 초기에 input이 적을 때는 loss에 큰 변화가 없고 40개 즈음부터 loss가 크게 튀는 모습을 볼 수 있습니다.
따라서 정보량이 늘어나면서 얻는 advantage보다 오버피팅으로 인한 disadvantage가 더 많다고 볼 수 있겠네요! 아마 layer수나 node수가 늘어나면 더 일찍 오버피팅이 시작될 것 같습니다. 반대로 layer수나 node수가 줄면 model capacity가 줄어드니까 아무래도 오버피팅은 줄 가능성이 높겠죠.

test set에서 loss의 크기가 대충 6백만 정도 되는 걸로 봐서, 아마 매일 2500원 정도의 차이가 난다고 볼 수 있겠네요. 카카오 주가가 대충 12만원이라고 치면 예측 가격과 2%정도 차이가 나네요. 사실 예측이 거의 의미가 없다고 봐도 무방..ㅋㅋ

저는 대충 한달 정도를 본다고 치고 input 개수를 20개로 잡겠습니다.(거래일 기준)

이제 앞서 임의로 고정해놓았던 layer와 node를 건드려볼 차례인데요,
사실 예전에 input개수를 30개로 두고 layer를 1,2,3,4개, node수는 128,64,32,16,8,4 등을 놓고 돌려본 적이 있는데 layer수는 4개 이상부터 아주 loss가 커져버려서 애초에 layer 수를 적게 놓고 돌렸습니다. 위의 64, 16은 그때 돌렸을 때 가장 loss가 적었던 hyperparameter setting이라 input수를 정할 때 그렇게 잡게 되었습니다.

정보 제공이 목적이 아니라 저를 위해 쓰는 글이기 때문에 layer와 node는 그냥 그대로 놓을게요
ㅋㅋ... 다시 코드 정리하기 귀찮..글도 길어지고..

아까 확인하지 못했던 test set loss가 더 작게 나오는 이유를 찾아볼게요!
우선 test set과 training set variance부터 확인해보겠습니다.
training set의 경우 분산이 4억(ㅎㄷㄷ..)이고, test set의 경우 분산이 2천만 정도네요. 이유는 기간의 차이일 겁니다. training set의 경우 거래일 기준 900일이고, test set의 경우 거래일 기준 100일이어서 아마 100일 동안의 가격 변동폭이 training set에 비해 적었던 것 같습니다. 분산이 20배 차이니 아무래도 당연히 test set loss가 적을 수밖에 없었던 것 같습니다.
(분산이 크면 loss가 크게 되는 이유도 추후에 설명됩니다.)

그럼 이제 loss를 트래킹하면서 training 횟수를 고민해봅시다.
epoch에 따른 loss를 그래프로 그려보면 다음과 같습니다.



아시다시피, 빨간색이 training loss, 파란색이 test loss입니다. loss값을 log에 넣어서 그렸는데도 불구하고 초반 5개(250 epoch분량)는 너무 튀어서 아예 빼고 그렸습니다.
5000 epoch이상부터는(x축에서는 100) loss가 튀는 걸 보면 아마 4000~5000 정도가 적당하지 싶습니다. 그래도 loss가 5000까지는 줄어드는 것처럼 보이기 때문에 5000으로 놓도록 하겠습니다.

이제 예측 가격과 실제 가격을 plotting해보도록 하겠습니다.


















p가 prediction, r이 real입니다. 예측치가 거의 전날 실제 종가를 따라가고 있다고 보면 될 것 같습니다. 언뜻 보면 굉장히 잘 예측하고 있는 것처럼 보이지만, 실은 전혀 유익하지 못한 예측이네요ㅋㅋ... 실제로 abs(예측치 - 실제 가격)의 sum은 80000 정도인데,
abs(예측치 - 전날종가)의 sum은 10000정도로 거의 전날 종가에서 조금 바꿔서 뱉는다고 봐도 무방하겠습니다...하하

이렇게 놓고 보니 training set보다 test set의 loss가 낮은 건 아마 변화율 차이 때문이라고 보는 게 맞겠네요. 분산이 정확히 일별 상승/하락폭을 얘기해주지는 않지만, 확인해보면 training set에서 일별 상승/하락폭이 더 클 게 분명합니다. test set의 loss가 더 작은 것은 아마 이것 때문이겠네요.

효율적은 발견은 아니지만 그래도 재미삼아 뉴럴넷을 토대로
매수, 매도 판단을 내려보도록 하겠습니다.


전날 종가가 다음날 시가와 같다는 전제하에, 예측치가 전날 종가보다 높으면 구매해서 오늘의 종가 가격으로 팔고, 낮다면 공매도해서 오늘의 종가 가격으로 사는 알고리즘을 구성해보았습니다. 결과는 처참하네요. 14500원 손실을 입었습니다. 같은 기간 첫날에 구매해서 계속 보유하고 있었다면 22500원을 벌었을 겁니다.

이 정도에서 마무리하면 좋을 것 같습니다.
close price를 아주 심플하게 MLP로 분석해본다면 이 정도가 될 것 같습니다.
뉴럴넷은 오늘의 종가를 그대로 내일의 종가로 뱉어버리네요.

모델을 구성해서, MLP가 근사해야 하는 함수가 좀 더 noise가 적게 끼게 된다면 아마
좀 더 나은 예측력을 보여줄 수 있으리라고 기대합니다.

댓글 없음:

댓글 쓰기