2020년 9월 13일 일요일

주가 예측 (2) - xgboost reg:squarederror, python, simulation


앞에서 예측이란 주제로 글을 작성해 보았습니다.

https://swlock.blogspot.com/2020/09/xgboost-regsquarederror.html

앞에 작성한 데이터를 실행시켜보고 그 결과가 보도록 하겠습니다.

predict_feature_reg.py 실행

C:\Users\USER\Documents\python\stock>python predict_feature_reg.py
('64bit', 'WindowsPE')
          Time  Price       Vol  SPrice  ...   Vol_lag10  SPrice_lag10  HPrice_lag10  LPrice_lag10
0     20200819  57800  16930719   59000  ...  19419694.0       57200.0       58100.0       57000.0
1     20200818  58400  25307825   58900  ...  21158940.0       57800.0       57900.0       56700.0
2     20200814  58000  15672548   58000  ...  21943345.0       59500.0       59600.0       57700.0
3     20200813  58700  22089460   59400  ...  19285354.0       59700.0       60100.0       59000.0
4     20200812  59000  18573934   58200  ...  36476611.0       60300.0       60400.0       58600.0
...        ...    ...       ...     ...  ...         ...           ...           ...           ...
6597  19940916   2280  27110458    2280  ...         NaN           NaN           NaN           NaN
6598  19940915   2260  56990850    2260  ...         NaN           NaN           NaN           NaN
6599  19940914   2214   5196078    2214  ...         NaN           NaN           NaN           NaN
6600  19940913   2168   3739216    2168  ...         NaN           NaN           NaN           NaN
6601  19940912   2122  19141830    2122  ...         NaN           NaN           NaN           NaN

[6602 rows x 61 columns]

실행시키면 predict.csv test.csv train.csv 3가지 파일이 생성 됩니다.


predict_xgboost_reg.py 실행 내용이 길어서 마지막 부분만 표시하였습니다.

[505]   eval-rmse:608.82898     train-rmse:0.00053
[506]   eval-rmse:608.82898     train-rmse:0.00053
[507]   eval-rmse:608.82898     train-rmse:0.00053
[508]   eval-rmse:608.82898     train-rmse:0.00053
[509]   eval-rmse:608.82898     train-rmse:0.00053
[510]   eval-rmse:608.82898     train-rmse:0.00053
[511]   eval-rmse:608.82898     train-rmse:0.00053
[512]   eval-rmse:608.82898     train-rmse:0.00053
Stopping. Best iteration:
[492]   eval-rmse:608.82898     train-rmse:0.00053

Total rmse 370672.713558

eval-rmse 608 정도 나오는데 train-rmse비해 수치상으로 높은 값입니다. 제가볼때는 훈련된 값으로 평가를 했을때 거의 예측이 안된다고 보는게 맞습니다.

결과로는 predict_xgboost_regtest_prey.csv 이런 파일이 생성됩니다. 해당값은 마지막에 예측된 Y값인 PreY 값이 들어갑니다.


지금부터는 지난번에 소개안한 내용입니다. 현재 데이터로 시뮬레이션을 해보도록 해보겠습니다.

원하는 목표가 보다 높다면 실제 구매해보고 이익이 얼마나 발생하는지 보는것입니다.

predict_simul_reg.py

#

import pandas as pd
import config

BASE_PATH = "./"

def resultx(x):
	pprice = x[0]+x[0] * config.P_SELLP/100.0# Price  팔아야 하는 목표값을 계산한다
	if pprice <= x[2] : return 1 # 목표값보다 예상값(PreY)이 커지면 구매표시를 한다.
	return 0


test_df = pd.read_csv(BASE_PATH+'predict_xgboost_regtest_prey.csv', header=0, encoding='utf8')

test_df['Buy'] = test_df[['Price','Y','PreY']].apply(resultx, axis=1)

test_df.to_csv("buy.csv", encoding='utf-8', index=False)

# 실제 구매했을때 얼마나 손익이 날 수 있는지 시뮬레이션을 하도록한다
rowcount = test_df.shape[0]

havetobuy = False
price = 0
buylist=[]
total = 0
for i in range(rowcount-1,0-1,-1):
	LPrice = test_df.iloc[i]['LPrice']
	HPrice = test_df.iloc[i]['HPrice']
	Time = test_df.iloc[i]['Time']
	# 이미 보유 하고 있으면
	if len(buylist) > 0 :
		# 팔 항목 있는지 살펴본다.
		removelist = []
		for buiedprice in buylist:
			pprice = buiedprice+buiedprice * config.P_SELLP/100.0
			mprice = buiedprice-buiedprice * config.M_SELLP/100.0
			if LPrice < mprice :
				total=total-config.M_SELLP
				removelist.append(buiedprice)
				print(Time,"sell",i,buiedprice,"-",LPrice)
			elif HPrice > pprice :
				total=total+config.P_SELLP
				removelist.append(buiedprice)
				print(Time,"sell",i,buiedprice,"+",HPrice)
		
		if len(removelist)>0:
			for item in removelist:
				buylist.remove(item)
				
	if havetobuy == True and len(buylist) < config.MONEY_TOTAL:
		LPrice = test_df.iloc[i]['LPrice']
		if price >= LPrice :
			buylist.append(price)
			pprice = price+price * config.P_SELLP/100.0
			mprice = price-price * config.M_SELLP/100.0
			print(Time,"havetobuy",i,price,"buy",mprice,pprice)
		else:
			print(Time,"havetobuy",i,price,LPrice,"dont buy")
	
	if test_df.iloc[i]['Buy'] > 0.5 :
		havetobuy = True
		price = test_df.iloc[i]['Price']
	else:
		havetobuy = False
		price = test_df.iloc[i]['Price']
	
print(total)
	

동작 원리에대해서 설명

팔아야 하는 목표값보다 예측값(PreY)이 높으면 Buy 항목에 1로 표시해둡니다. buy.csv의 마지막 컬럼

마지막 날짜에서부터 Buy컬럼 값을 읽어서 구매해야한다고 판단을 하면 그 다음 날짜에 현재 날짜의 종가로 구매를 합니다.

이때 다음 날짜의 주식의 LPrice , HPrice가 있는데 이 값 범위에 들어야만 구매가 가능합니다. 만약 구매하지 못하면 "dont buy" 이런 문구가 나오게 됩니다.

보유하고 있는 주식은 매번 구매 했던 값의 목표치 값인 아래 두개 값보다 떨어지거나 올라가면 팔게 됩니다. 여기 예제에서는 6%로 잡아놨습니다. P_SELLP, M_SELLP 참고

pprice = buiedprice+buiedprice * config.P_SELLP/100.0

mprice = buiedprice-buiedprice * config.M_SELLP/100.0

MONEY_TOTAL 이 값은 구매시의 횟수를 나타냅니다. 즉 구매를 한번하고 나면 해당값이 줄어들고 0이 되면 더 이상 구매할 수 없게 됩니다. 중첩해서 구매 가능한 횟수를 나타냅니다.

config.py

X_M_PREDAYES=5 # 예측할때 과거 몇일을 가지고 학습 데이터를 만들지 결정하는 값
Y_O_POSTDAYES=5# 예측할때 앞으로의 몇일을 가지고 결과Y를 만들지 결정하는 값

#이익이 났을때 판매 가격 %
P_SELLP=6
#손해가 났을태 판매 가격 %
M_SELLP=6

COUNT_TEST_DATA = 600 # 테스트 검증를 위한 데이터 갯수

# simulation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

MONEY_TOTAL = 2


최종 결과값입니다.

C:\Users\USER\Documents\python\stock>python predict_simul_reg.py
20180702.0 havetobuy 521 46650.0 buy 43851.0 49449.0
20180703.0 havetobuy 520 45550.0 45750.0 dont buy
20180709.0 havetobuy 516 44900.0 45200.0 dont buy
20180712.0 havetobuy 513 46000.0 buy 43240.0 48760.0
20180816.0 sell 489 46650.0 - 43700.0
20180817.0 havetobuy 488 44250.0 buy 41595.0 46905.0
20180828.0 sell 481 44250.0 + 46950.0
20180910.0 havetobuy 472 44900.0 45000.0 dont buy
20180913.0 havetobuy 469 44550.0 buy 41877.0 47223.0
20180920.0 sell 464 44550.0 + 47600.0
20181008.0 havetobuy 456 44700.0 buy 42018.0 47382.0
20181011.0 sell 454 46000.0 - 43100.0
20181011.0 havetobuy 454 45300.0 buy 42582.0 48018.0
20181023.0 sell 446 45300.0 - 42550.0
20181023.0 havetobuy 446 43550.0 buy 40937.0 46163.0
20181025.0 sell 444 44700.0 - 40550.0
20181025.0 sell 444 43550.0 - 40550.0
20181204.0 havetobuy 416 43250.0 buy 40655.0 45845.0
20181206.0 sell 414 43250.0 - 40450.0
20190305.0 havetobuy 358 44850.0 buy 42159.0 47541.0
20190306.0 havetobuy 357 44250.0 buy 41595.0 46905.0
20190322.0 sell 345 44250.0 + 47000.0
20190403.0 havetobuy 337 45750.0 45800.0 dont buy
20190405.0 sell 335 44850.0 + 47550.0
20190419.0 havetobuy 325 45600.0 buy 42864.0 48336.0
20190423.0 havetobuy 323 45350.0 buy 42629.0 48071.0
20190509.0 sell 313 45600.0 - 42450.0
20190509.0 sell 313 45350.0 - 42450.0
20190605.0 havetobuy 294 43450.0 43700.0 dont buy
20190614.0 havetobuy 288 43750.0 buy 41125.0 46375.0
20190627.0 sell 279 43750.0 + 46600.0
20190711.0 havetobuy 269 45550.0 46150.0 dont buy
20190801.0 havetobuy 254 45350.0 buy 42629.0 48071.0
20190802.0 havetobuy 253 45200.0 buy 42488.0 47912.0
20190806.0 sell 251 45350.0 - 42500.0
20190806.0 havetobuy 251 43950.0 buy 41313.0 46587.0
20190909.0 sell 228 43950.0 + 47000.0
20190919.0 sell 222 45200.0 + 49200.0
20191121.0 havetobuy 179 52000.0 buy 48880.0 55120.0
20191217.0 sell 161 52000.0 + 56700.0
-6

최종 결과가 -6은 -6% 손해라는 의미 입니다.


결론적으로 손해를 봤지만, 적용해서 사용하기엔 몇가지 문제가 있습니다. 학습 데이터가 너무 적다는것입니다. 일주일에 5개씩 10년해도 1만개도 채 되지 않는 양이라 훈련을 하기에는 무리가 있습니다. 

회귀란 이전 데이터를 통해 미래를 예측하게 됩니다. 주가의 특성상 과거 데이터값만 고려하면 현재의 값과는 굉장히 많이 다릅니다. 예를들어 10년전에 100원 하던 주가가 지금은 1000원 하게 되니 당연히 과거에 데이터로는 현재의 회귀 모델에 맞지 않게 되는것 입니다. 

그럼 생각해본 해결책은 비슷한 성향의 여러가지 종목을 하나의 종목처럼 추가하여 종목명을 구별하여 넣어 학습데이터를 늘려보는 방법입니다. 다른 하나는 입력데이터를 정규화 하는 방법을 생각할 수 있습니다.


댓글 없음:

댓글 쓰기