SVM(서포트 벡터 머신)을 활용한 주가 방향 예측

2020. 7. 28. 23:24금융 데이터 분석

반응형

이번 포스팅에서는 SVM을 활용하여 주가의 방향을 예측해보도록 하겠습니다. 추가적으로, 삼성전자 주가를 예측하기 위해 삼성전자 주가 정보만 이용하는 것이 아니라 KOSPI 지수 정보도 함께 활용하여 주가의 방향을 예측해보겠습니다.

이번 포스팅에서 활용하는 변수는 아래의 자료를 참조하여 만들었습니다. 아래 자료에서 활용한 정보와 완전히 일치하진 않지만, 아이디어를 차용하여 단순 가격 데이터가 아니라 가격데이터를 활용하여 예측에 활용할 변수를 만들었습니다.

Madge, Saahil, and Swati Bhatt. "Predicting stock price direction using support vector machines." Independent work report spring (2015).(https://www.cs.princeton.edu/sites/default/files/uploads/saahil_madge.pdf)

먼저 필요한 Module과 데이터를 가지고 오겠습니다. 이번에 KOSPI 정보는 앞선 포스트(https://direction-f.tistory.com/6)에서 정리한 것처럼 수동으로 Yahoo finance에서 다운로드 받아서 활용하였습니다.

import pandas as pd
import numpy as np
import os
import matplotlib.pyplot as plt
from sklearn import svm
from sklearn import metrics

## 데이터 불러오기
os.chdir(".../new_stock")
sam = pd.read_csv("samsung.csv")
sam=sam.sort_index(ascending=False)
sam=sam.reset_index()
sam=sam.drop(["index"], axis=1)
sam.rename(columns ={"종가":"Close"}, inplace =True)
kospi = pd.read_csv("KS11.csv")

## 종가데이터만 별도로 추출
data_sam = sam[["Close"]]
data_kospi = kospi[["Close"]]

그 다음으로 가격이 증가했는지 떨어졌는지 방향을 나타내는 칼럼을 추가하겠습니다. 전일보다 가격이 오르면 "1", 떨어지면 "-1"이 입력되도록 하겠습니다. 첫 날의 데이터는 그 전날 데이터가 없기 때문에 임의로 "0"을 집어 넣었습니다.

def make_return(data):
    return_list =[0]
    
    for i in range(len(data)-1):
        if (data.iloc[i+1]["Close"]/data.iloc[i]["Close"])-1 >=0:
            return_list.append(1)

        else :
            return_list.append(-1)
        
    return return_list   
    
    data_sam["return"]=make_return(data_sam)
    data_kospi["return"]=make_return(data_kospi)

그 다음으로 Window size를 5로 하여 1열인 데이터를 5열의 가격 데이터를 가지도록 재구성합니다. 재구성한 데이터를 활용하여 이번에 추측에 활용할 변수를 만들고자 합니다. 아래 코드에서 feature_list2를 구성한 이유는 가격 데이터 뿐만 아니라 return 정보를 활용해서도 활용할 변수를 만들고자 하기 때문입니다.

def make_data(data, window_size=5):
    feature_list =[]
    feature_list2 =[]
    label_list=[]    
    
    if "return" in data.columns:
    
        for i in range(len(data)-5):
            feature_list.append(np.array(data.iloc[i:i+window_size]["Close"]))
            feature_list2.append(np.array(data.iloc[i:i+window_size]["return"]))
            label_list.append(np.array(data.iloc[i+window_size]["return"]))

        data_X = np.array(feature_list)
        data_X2 = np.array(feature_list2)
        data_Y = np.array(label_list)
        
        return data_X, data_X2, data_Y 
    
    else : 
        
        for i in range(len(data)-5):
            feature_list.append(np.array(data.iloc[i:i+window_size]["Close"]))
            
        data_X = np.array(feature_list)
        
    
        return data_X
        
sam_X, sam_X2,sam_Y = make_data(data_sam)
kospi_X, kospi_X2, kospi_Y = make_data(data_kospi)

만든 데이터를 DataFrame으로 변경하고, 이제 활용할 변수를 만들도록 하겠습니다. 아래는 우리가 활용하고자 하는 변수에 대한 List 입니다.

출처:Predicting stock price direction using support vector machines

출처의 자료에서는 n의 값을 변경하면서 실험을 하지만, 저는 window_size를 5로 한정하여 예측해야하는 시점보다 5일전 자료부터 전날 자료까지 총 5일치의 자료만을 활용하는 것으로 한정하겠습니다.

먼저 Volatility를 만듭니다.

## DataFrame 변환
sam_X = pd.DataFrame(sam_X, columns=["1st", "2nd", "3rd","4th","5th"])
sam_X2 = pd.DataFrame(sam_X2, columns=["1st", "2nd", "3rd","4th","5th"])
sam_Y = pd.DataFrame(sam_Y, columns=["label"])
kospi_X = pd.DataFrame(kospi_X,columns=["1st", "2nd", "3rd","4th","5th"])
kospi_X2 = pd.DataFrame(kospi_X2,columns=["1st", "2nd", "3rd","4th","5th"])
kospi_Y = pd.DataFrame(kospi_Y, columns=["label"])

##Volatility 생성
def make_stock_volatility(row):
    a=0
    for i in range(5-1):
        a+=(row[i+1]-row[i])/row[i]
    stock_volatility=a/4*100
    return stock_volatility

sam_X["stock_volatility"]=sam_X.apply(lambda x : make_stock_volatility(x), axis=1)
kospi_X["index_volatility"]=kospi_X.apply(lambda x : make_stock_volatility(x), axis=1)

다음으로 Momentum을 만듭니다.

## Momentum 생성
def make_stock_momentum(row):
    a = sum(row)/5
    return a 

sam_X2["stock_momentum"]=sam_X2.apply(lambda x : make_stock_momentum(x), axis=1)
kospi_X2["index_monentum"]=kospi_X2.apply(lambda x : make_stock_momentum(x), axis=1)

이제 train 데이터와 test 데이터를 나누고 Support Vector Machine을 활용하여 예측해보도록 하겠습니다.

##Base model
clf = svm.SVC(kernel ="rbf", gamma =2.0, C= 1000)
clf.fit(train_X.values, train_Y.values.ravel())

y_pred = clf.predict(test_X)
print("Accuracy:",metrics.accuracy_score(test_Y, y_pred))

gamma와 C는 우리가 입력해야하는 Parameter로써 위의 모델에서는 임의로 입력한 값입니다. 이때 정확도는 47%가 나왔습니다. 역시 주가의 방향을 예측하는 것은 어려운 것 같습니다..

이제 GridSearchCV를 활용하여 최적화된 파라미터를 찾아서 모델을 Fitting 해보도록 하겠습니다.

from sklearn.model_selection import cross_val_score, GridSearchCV

svm_parameters = [{"C" : [1,10,100,1000],

                      "gamma" : [0.1, 1, 3, 5, 10] }]
                      
                      
svm_grid = GridSearchCV(estimator = svm.SVC(), param_grid = svm_parameters, scoring ="accuracy", cv=10, n_jobs=1, iid=False)
svm_grid_result =svm_grid.fit(train_X, train_Y.values.ravel())
best_svm_parameters = svm_grid_result.best_params_
svm_score = svm_grid_result.best_score_

print(svm_score) # 0.5692307692307692
print(svm_grid_result.best_params_) # {'C': 1, 'gamma': 1}

best_svm = svm.SVC(C=svm_grid_result.best_params_["C"], gamma =svm_grid_result.best_params_["gamma"] )
best_svm.fit(train_X, train_Y.values.ravel())

y_pred_best = best_svm.predict(test_X)
print("Accuracy:",metrics.accuracy_score(test_Y, y_pred_best))

최적화된 Parameter로 Test를 해본 결과 50%의 정확도가 나왔습니다.

 

참조)

https://www.cs.princeton.edu/sites/default/files/uploads/saahil_madge.pdf

https://www.datacamp.com/community/tutorials/svm-classification-scikit-learn-python

반응형