코딩걸음마

주식 정보 불러와서 미래수익률 예측기 만들기 (with Pykrx) 본문

나만의 프로그램

주식 정보 불러와서 미래수익률 예측기 만들기 (with Pykrx)

코딩걸음마 2022. 6. 19. 16:06
728x90

간단한 아이디어가 갑자기 번뜩 떠올랐다.

기술적분석한 값을 input data로 두고 target으로 미래수익률을 두고

모델을 훈련시키면 좋을거 같은데?



이 간단한 생각을 적용해서 모델을 만들어 봤다.

 

1. 필요한 모듈 불러오기

# 우선 모듈 설치부터!
# !pip install mpl_finance
# !pip install matplotlib
# !pip install IPython
# !pip install datetime
# !pip install pandas_datareader
# !pip install pykrx
# !pip install ta
# !pip install --upgrade mplfinance

#모듈 불러오기
import matplotlib.pyplot as plt
import pandas as pd
from pandas_datareader import data 
from datetime import datetime
from pykrx import stock
import numpy as np
import ta
from tqdm import tqdm

2. 기초 변수 가져오기

#오늘 날짜를 가져오는 함수
today = str(datetime.now())
today = today.replace("-","")[:8]

#년도를 바꾸는 함수
def year_change(date,x):
  year = str(int(date[:4])-x)
  month_day = date[4:]
  return str(year+month_day)

#종목명 -> 티커 반환 함수
def stock_name(name,date=today):
  df = stock.get_market_price_change(date,date)
  return df[df["종목명"]==name].index[0]

#날짜 형식 변경
def date_split(x):
  x = x[2:]
  return x

#int 형식 변경

def change_to_int(x):
  if x>-1:
    x = int(x)
    return x

3. 사용자 입력 Data (여기에 내가 궁금한 자료를 입력하자)

#-----[분석 Data 입력구간]-------------------------------------------------------------------------------------------------------------------
#Data 기간
year = 10

#x일후 수익률 예측
next_day =1

#분석 종료일자 (자동입력)
end_date = "20220608" #today

#--------------------------------------------------------------------------------------------------------------------------

#분석 시작일자
start_date = year_change(end_date,year) #10년 data 가져오기

4. 종목 리스트 불러오기

# kospi 종목 리스트
kospi_tickers = stock.get_market_ticker_list(end_date, market="KOSPI")

# kosdaq 종목 리스트
kodaq_tickers = stock.get_market_ticker_list(end_date, market="KOSDAQ")

tickers = kospi_tickers + kodaq_tickers


# 빈 데이터 프레임 생성
data = pd.DataFrame(columns=['pc', 'MA5_dis','MA60_dis', ,'MA224_dis','RSI', 'macd_signal',
 					'bol_h','bol_l', 'past_1day_pc', 'past_2day_pc', 'past_3day_pc', 'past_4day_pc', 'past_5day_pc', 'next_1day_pc', 'next_2day_pc', 'next_3day_pc', 'next_4day_pc', 'next_5day_pc'])

5. 주가 패턴 Data 수집

처음 모델을 무작정 돌렸을 때 값이 생각보다 만족스럽게 나오지 않았다.

Scaling 문제인가?

아니면 신규상장 종목의 data 부족?

액면분할 종목의 가격 왜곡현상?

 

 

이 부분을 고려하여

분석 data를 백분율로 scaling 해주고

특정 년수 이하의 종목은 제외하고

액면분할 경험이 있던 종목도 모두 제외하여 분석했다.

 

working_day = year*240



for ticker in tqdm(tickers):
  df_real = stock.get_market_ohlcv(start_date,end_date, ticker, adjusted=False)
  if len(df_real) > working_day:
    df=df_real.copy()
    try:

        df_detail = stock.get_stock_major_changes(ticker)
        if df_detail['액면변경전'].sum()==0:
            print("액면분할 없음")

            #등락률 이름 변경
            df['pc'] = df['등락률']
        #     print("pc_complete")

            #평균선 괴리도(%)
            df['MA5_dis'] = (df['종가']-df['종가'].rolling(5).mean())/df['종가']
            df['MA60_dis'] = (df['종가']-df['종가'].rolling(60).mean())/df['종가']
            df['MA224_dis'] = (df['종가']-df['종가'].rolling(224).mean())/df['종가']
        #     print("MA_complete")

            #RSI
            df['RSI'] = ta.momentum.rsi(df['종가'])
            df['RSI'] = (df['RSI'].map(change_to_int)+0.000000001)/100
        #     print("RSI_complete")

            #macd_signal
            df['macd_signal'] = ta.trend.macd_signal(df['종가'])/df['종가']
        #     print("MACD_complete")

            #bolinzer band
            df['bol_h'] = ta.volatility.bollinger_hband(df['종가'])/df['종가']
            df['bol_l'] = ta.volatility.bollinger_lband(df['종가'])/df['종가']
        #     print("bolinzer_complete")


            #지난 5일 동안의 수익률 
            df['past_1day_pc'] = (df["종가"].shift(+next_day)-df["종가"])/df["종가"]*100
            df['past_2day_pc'] = (df["종가"].shift(+next_day+1)-df["종가"])/df["종가"]*100
            df['past_3day_pc'] = (df["종가"].shift(+next_day+2)-df["종가"])/df["종가"]*100
            df['past_4day_pc'] = (df["종가"].shift(+next_day+3)-df["종가"])/df["종가"]*100
            df['past_5day_pc'] = (df["종가"].shift(+next_day+4)-df["종가"])/df["종가"]*100
        #     print("past_complete")

            #현재시점부터 보유 5일후 수익률 (target)
            df['next_1day_pc'] = (df["종가"].shift(-next_day)-df["종가"])/df["종가"]*100
            df['next_2day_pc'] = (df["종가"].shift(-next_day-1)-df["종가"])/df["종가"]*100
            df['next_3day_pc'] = (df["종가"].shift(-next_day-2)-df["종가"])/df["종가"]*100
            df['next_4day_pc'] = (df["종가"].shift(-next_day-3)-df["종가"])/df["종가"]*100
            df['next_5day_pc'] = (df["종가"].shift(-next_day-4)-df["종가"])/df["종가"]*100
        #     print("next_complete")

            df = df.iloc[223:-5,7:]

            data = data.append(df)
            print(f"{ticker}_complete")

    except:
        continue

    
   
data.to_csv('stock_data_5days.csv')

6. 머신러닝 분석 (lightgbm 적용)

.

df = pd.read_csv('stock_data.csv')
df.head(2)

X_features = df.iloc[:,1:-11]
Y_target = df.iloc[:,-1:]


# lightGBM <- fix
from sklearn.metrics import mean_absolute_error
from lightgbm.sklearn import LGBMRegressor
from sklearn.model_selection import train_test_split
train_x, test_x, train_y, test_y = train_test_split(
    X_features, Y_target, test_size=0.3, random_state=123)  # test_size 0.3  30%가 test set

#모델에 data 넣기
model = LGBMRegressor().fit(train_x, train_y)
pred = model.predict(test_x)
print(f"model_ LGBMRegressor    MAE : {mean_absolute_error(test_y, pred)}")

MAE 오차는 평균적으로 위/아래로 MAE%만큼 오차가 있다는 뜻이다

낮을수록 모델이 좋은 성능인 것으로 해석할 수 있다.

 

7. 개별종목의 Data 가져오기

224일선의 정보를 가져오기 위해서 2년치 data를 불러온다.

# 종목명 -> 티커 반환 함수
def stock_name(name, date=today):
    df = stock.get_market_price_change(date, date)
    return df[df["종목명"] == name].index[0]


# -----[분석 Data 입력구간]-------------------------------------------------------------------------------------------------------------------
# Data 기간
year = 2


# 분석 종료일자 (자동입력)
  # today 당일 수급데이터가  없음

start_date = year_change(end_date, year)  # 10년 data 가져오기
# --------------------------------------------------------------------------------------------------------------------------


# 개별 종목 티커 반환
ticker = stock_name(name, end_date)
# kospi 종목 리스트
kospi_tickers = stock.get_market_ticker_list(end_date, market="KOSPI")
# kosdaq 종목 리스트
kodaq_tickers = stock.get_market_ticker_list(end_date, market="KOSDAQ")

ticker = stock_name(name, end_date)


df_now = stock.get_market_ohlcv(start_date, end_date, ticker, adjusted=False)

# 등락률 이름 변경
df_now['pc'] = df_now['등락률']

# 평균선 괴리도(%)
df_now['MA5_dis'] = (df_now['종가']-df_now['종가'].rolling(5).mean())/df_now['종가']
df_now['MA60_dis'] = (df_now['종가']-df_now['종가'].rolling(60).mean())/df_now['종가']
df_now['MA224_dis'] = (df_now['종가']-df_now['종가'].rolling(224).mean())/df_now['종가']


# RSI
df_now['RSI'] = ta.momentum.rsi(df_now['종가'])
df_now['RSI'] = df_now['RSI'].map(change_to_int)

# macd_signal
df_now['macd_signal'] = ta.trend.macd_signal(df_now['종가'])/df_now['종가']

# bolinzer band
df_now['bol_h'] = ta.volatility.bollinger_hband(df_now['종가'])/df_now['종가']
df_now['bol_l'] = ta.volatility.bollinger_lband(df_now['종가'])/df_now['종가']

# 일목균형표

#지난 5일 동안의 수익률 
df_now['past_1day_pc'] = (df_now["종가"].shift(+next_day)-df_now["종가"])/df["종가"]*100
df_now['past_2day_pc'] = (df_now["종가"].shift(+next_day+1)-df_now["종가"])/df["종가"]*100
df_now['past_3day_pc'] = (df_now["종가"].shift(+next_day+2)-df_now["종가"])/df["종가"]*100
df_now['past_4day_pc'] = (df_now["종가"].shift(+next_day+3)-df_now["종가"])/df["종가"]*100
df_now['past_5day_pc'] = (df_now["종가"].shift(+next_day+4)-df_now["종가"])/df["종가"]*100
print("past_complete")



#현재시점부터 보유 5일후 수익률 (target)
df_now['next_1day_pc'] = (df_now["종가"].shift(-next_day)-df_now["종가"])/df["종가"]*100
df_now['next_2day_pc'] = (df_now["종가"].shift(-next_day-1)-df_now["종가"])/df["종가"]*100
df_now['next_3day_pc'] = (df_now["종가"].shift(-next_day-2)-df_now["종가"])/df["종가"]*100
df_now['next_4day_pc'] = (df_now["종가"].shift(-next_day-3)-df_now["종가"])/df["종가"]*100
df_now['next_5day_pc'] = (df_now["종가"].shift(-next_day-4)-df_now["종가"])/df["종가"]*100
print("next_complete")

df_now_data = df_now.iloc[223:-5, 7:]

8. 5일 후, 수익률 추정

 

# 오늘 data를 입력하여 내일 데이터를 추정하기
df_today = df_now.iloc[-1:, 7:-11]

pred_next_5day = lgbm_x_day(5).predict(df_today)

print(f"5일후 수익률 예측 :  {pred_next_5day[0]:.2}%")
주식은 머신러닝/딥러닝을 공부하기에 참 좋은 Data임에 틀림없다. 
끝없이 생산되고 결측치나 오류가 적기 때문이다.


 

728x90
Comments