Stock Price Direction Predictor
주가 방향 예측 변수
- 전날의 종가 또는 거래량 데이터를 이용하여
다음날 주가 방향을 예측한다.
- 입력변수는 종가 혹은 거래량이다. (둘 다 사용할 수도 있다.)
* Required Libraries
# stock_price_direction_predictor.py
import os, sys, datetime
import pandas as pd
import numpy as np
import stock_data as sd
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import LinearSVC, SVC
Dataset (데이터셋)
- 학습과 테스트에 사용될 데이터의 집합을 의미한다.
- 만들어진 데이터셋을 일정 비율로 나누어 학습용 데이터셋과 테스트용 데이터셋으로 구분짓는다.
(일반적으로, 학습용 : 테스트용 = 3 : 1 의 비율을 많이 사용한다.)
- 학습에 너무 적은 비중을 두면 Underfitting(과소적합) 문제가 발생할 수 있고,
학습에 너무 많은 비중을 두면 Overfitting(과적합) 문제가 발생할 수 있다.
\(\texttt{make_dataset()}\) Function
# stock_price_direction_predictor.py
def make_dataset(df, time_lags=5):
'''
데이터 프레임을 받아 학습과 테스트에 사용할 DataFrame으로 만든다.
[Inputs]
df : Data Frame (*.data File)
time_lag : 현재일 기준 과거일자 (time_lag=5 : 5일전 데이터)
[Outputs]
Close_Direction : 향후 주가의 방향 (하방 = -1, 상방 = +1)
Volume_Direction : 향후 거래량의 방향 (하방 = -1, 상방 = +1)
'''
df_lag = pd.DataFrame(index=df.index)
df_lag["Close"] = df["Close"] # 종가
df_lag["Volume"] = df["Volume"] # 거래량
df_lag["Close_Lag%s" % str(time_lags)] = df["Close"].shift(time_lags) # 사용자 지정 종가
df_lag["Close_Lag%s_Change" % str(time_lags)] = df_lag["Close_Lag%s" % str(time_lags)].pct_change()*100.0 # 사용자 지정 거래량
df_lag["Volume_Lag%s" % str(time_lags)] = df["Volume"].shift(time_lags)
df_lag["Volume_Lag%s_Change" % str(time_lags)] = df_lag["Volume_Lag%s" % str(time_lags)].pct_change()*100.0
df_lag["Close_Direction"] = np.sign(df_lag["Close_Lag%s_Change" % str(time_lags)])
df_lag["Volume_Direction"] = np.sign(df_lag["Volume_Lag%s_Change" % str(time_lags)])
return df_lag.dropna(how='any')
- 주가 데이터 파일을 입력받아 학습과 테스트에 사용 가능한 형태로 만들어 리턴하는 함수이다.
* \(\texttt{pct_change()}\) Method (\(\texttt{pandas}\) Library)
- 주어진 데이터의 상대적 변화량(%)을 계산하는 함수이다.
\(\texttt{split_dataset()}\) Function
# stock_price_direction_predictor.py
def split_dataset(df, input_column_array, output_column, split_ratio):
'''
데이터 셋을 받아, 사용자가 지정한 비율로 학습용 데이터셋과 테스트용 데이터셋으로 나누어 리턴한다.
[Inputs]
df : Data Frame (*.data File)
input_column_array : df의 칼럼 이름들이 저장된 배열
output_column : 출력변수로 사용할 칼럼의 이름
split_ratio : 전체 데이터셋에서 학습용 데이터셋이 차지하는 비율 [0.0, 1.0]
[Outputs]
X_train : 학습에 사용할 입력변수
X_test : 테스트에 사용할 입력변수
Y_train : 학습에 사용할 출력변수
Y_test : 테스트에 사용할 출력변수
'''
split_date = get_date_by_percent(df.index[0], df.index[df.shape[0]-1], split_ratio)
input_data = df[input_column_array]
output_data = df[output_column]
X_train = input_data[input_data.index < split_date]
X_test = input_data[input_data.index >= split_date]
Y_train = output_data[output_data.index < split_date]
Y_test = output_data[output_data.index >= split_date]
return X_train, X_test, Y_train, Y_test
def get_date_by_percent(start_date, end_date, percent):
'''
시작일과 마감일 사이에 비율에 해당되는 날짜를 리턴한다.
[Inputs]
start_date : 시작일
end_date : 마감일
percent : 하위 백분율 [0.0, 1.0]
[Outputs]
target_date : 하위 백분율에 대응되는 날짜
'''
days = (end_date - start_date).days
target_days = np.trunc(days * percent)
target_date = start_date + datetime.timedelta(days=target_days)
return target_date
- 데이터셋을 학습용 데이터셋과 테스트용 데이터셋으로 분할하는 함수이다.
- 주가 데이터는 시계열 데이터이기 때문에 데이터를 분할할 때 무작위로 추출하지 않고,
시간을 기준으로 나누어야 한다.
Machine Learning (기계 학습)
- \(\texttt{fit(input_data, output_data)}\) 함수를 통해 학습용 데이터셋을 알고리즘에 적용하여 학습시킨다.
# stock_price_direction_predictor.py
def do_logistic_regression(x_train, y_train):
'''
로지스틱 회귀 알고리즘과 학습용 데이터셋을 기반으로 학습된 모델을 리턴한다.
[Inputs]
x_train : 입력될 학습용 데이터
y_train : 입력 데이터에 기대되는 출력 데이터
[Outputs]
classifier : 학습이 완료된 모델
'''
classifier = LogisticRegression()
classifier.fit(x_train, y_train)
return classifier
def do_random_forest(x_train, y_train):
'''
랜덤 포레스트 알고리즘과 학습용 데이터셋을 기반으로 학습된 모델을 리턴한다.
[Inputs]
x_train : 입력될 학습용 데이터
y_train : 입력 데이터에 기대되는 출력 데이터
[Outputs]
classifier : 학습이 완료된 모델
'''
classifier = RandomForestClassifier()
classifier.fit(x_train, y_train)
return classifier
def do_svm(x_train, y_train):
'''
SVM 알고리즘과 학습용 데이터셋을 기반으로 학습된 모델을 리턴한다.
[Inputs]
x_train : 입력될 학습용 데이터
y_train : 입력 데이터에 기대되는 출력 데이터
[Outputs]
classifier : 학습이 완료된 모델
'''
classifier = SVC()
classifier.fit(x_train, y_train)
return classifier
Test (테스트)
# stock_price_direction_predictor.py
def test_classifier(classifier, x_test, y_test):
pred = classifier.predict(x_test)
hit_count = 0
total_count = len(y_test)
for index in range(total_count):
if(pred[index]) == (y_test[index]):
hit_count = hit_count + 1
hit_ratio = hit_count/total_count
score = classifier.score(x_test, y_test)
return hit_ratio, score
Execution (실행)
# stock_price_direction_predictor.py
if __name__ == '__main__':
for time_lags in range(1, 6):
print('- Time Lags=%s' % (time_lags))
for company in ['samsung', 'hanmi']:
df_company = sd.load_stock_data('%s.data' % (company))
df_dataset = make_dataset(df_company, time_lags)
X_train, X_test, Y_train, Y_test = split_dataset(df_dataset, ['Close_Lag%s' % (time_lags)], 'Close_Direction', 0.75)
# print X_test
lr_classifier = do_logistic_regression(X_train, Y_train)
lr_hit_ratio, lr_score = test_classifier(lr_classifier, X_test, Y_test)
rf_classifier = do_random_forest(X_train, Y_train)
rf_hit_ratio, rf_score = test_classifier(rf_classifier, X_test, Y_test)
svm_classifier = do_svm(X_train, Y_train)
svm_hit_ratio, svm_score = test_classifier(svm_classifier, X_test, Y_test)
print('%s : Hit Ratio - Logistic Regression=%0.2f, RandomForest=%0.2f, SVM=%0.2f' % (company, lr_hit_ratio, rf_hit_ratio, svm_hit_ratio))
Reference: 머신러닝을 이용한 알고리즘 트레이딩 시스템 개발
(안명호, 류미현 저, 한빛미디어, 2016)