diff --git a/Simulation.py b/Simulation.py index dbcaff0..5c6eeec 100644 --- a/Simulation.py +++ b/Simulation.py @@ -1,25 +1,22 @@ from math import nan -from datetime import datetime, timedelta -import copy import pandas as pd import plotly.graph_objects as go from plotly import subplots -import sqlite3 import os from hts.HTS import HTS +from stock.util.Stock2Vector import Stock2Vector from hts.BuySellChecker import BuySellChecker class Simulation (HTS): - + stock2Vector = None buySellChecker = None - stock_code = None - def __init__(self, RESOURCE_PATH, stock_code): + def __init__(self, RESOURCE_PATH): super().__init__(RESOURCE_PATH) + self.stock2Vector = Stock2Vector(RESOURCE_PATH) self.buySellChecker = BuySellChecker() - self.stock_code = stock_code self.RESOURCE_PATH = RESOURCE_PATH #self.connect() return @@ -129,30 +126,19 @@ class Simulation (HTS): return - def getRealTime(self, stock_code, today, LAST_DATA=None): - if LAST_DATA is not None: - result = copy.deepcopy(LAST_DATA) - else: - result = {"check": set(), "time": [], "open": [], "close": [], "high": [], "low": [], "vol": []} + def simulate(self, stock_code, today): + LAST_DATA = self.stock2Vector.getLastData(stock_code, today) - self.getDBData(stock_code, today, result) - - return result - - - def simulate(self, today): - LAST_DATA = self.getLastData(self.stock_code, today) - - result = self.getRealTime(self.stock_code, today, LAST_DATA) + result = self.stock2Vector.getRealTime(stock_code, today, LAST_DATA) # 규칙 기반의 분석을 통해서 볼린저밴드 상/하단을 계산한다. data = self.buySellChecker.analyzeByRule(result) # 사야 할 시점과 팔아야 할 시점을 체크한다. - bsLine, data = self.buySellChecker.checkTransaction(data, self.stock_code, False) + bsLine, data = self.buySellChecker.checkTransaction(data, stock_code, False) # 그래프를 그린다. - self.draw(self.stock_code, today, data, bsLine) + self.draw(stock_code, today, data, bsLine) return @@ -165,13 +151,13 @@ if __name__ == "__main__": stock_codes = { # 252670 # 122630 - "122630": ['20220725'], + "122630": ['20220729'], } for stock_code in stock_codes: - simulation = Simulation(RESOURCE_PATH, stock_code) + simulation = Simulation(RESOURCE_PATH) for given_day in stock_codes[stock_code]: - simulation.simulate(given_day) + simulation.simulate(stock_code, given_day) print ("done...") diff --git a/StockTrainer.py b/StockTrainer.py new file mode 100644 index 0000000..e9348e4 --- /dev/null +++ b/StockTrainer.py @@ -0,0 +1,83 @@ +import os +import keras +import numpy as np +from stock.util.Stock2Vector import Stock2Vector +from classification_models.keras import Classifiers + +class StockTrainer: + + RESOURCE_PATH = None + stock2Vector = None + + def __init__(self, RESOURCE_PATH): + self.RESOURCE_PATH = RESOURCE_PATH + self.stock2Vector = Stock2Vector(RESOURCE_PATH) + return + + def getDataset(self, stock_code): + df, minmax_df = self.stock2Vector.makeTrainData(stock_code) + + TOTAL_X, TOTAL_Y = [], [] + for key in df: + if key == "date": + continue + elif key == "label": + TOTAL_Y.append(df[key].tolist()) + else: + TOTAL_X.append(df[key].tolist()) + + X, Y = [], [] + for i in range(299, len(TOTAL_X[0])): + temp_X, temp_Y = np.zeros((299, 299)), np.zeros(0) + idx = 0 + for j in range(i-299, i): + for k in range(len(TOTAL_X)): + temp_X[k][idx] = TOTAL_X[k][j] + idx += 1 + X.append(temp_X) + Y.append(TOTAL_Y[i]) + + + + + return X, Y + + def train(self, stock_code): + ResNet18, preprocess_input = Classifiers.get('inceptionresnetv2') + + X, Y = self.getDataset(stock_code) + + X = preprocess_input(X) + + n_classes = 3 + + # build model + base_model = ResNet18(input_shape=(299, 299, 3), weights='imagenet', include_top=False) + x = keras.layers.GlobalAveragePooling2D()(base_model.output) + output = keras.layers.Dense(n_classes, activation='softmax')(x) + model = keras.models.Model(inputs=[base_model.input], outputs=[output]) + + # train + model.compile(optimizer='SGD', loss='categorical_crossentropy', metrics=['accuracy']) + model.fit(X, Y) + + return + + +if __name__ == "__main__": + PROJECT_HOME = os.path.join(os.path.dirname(__file__)) + RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources") + + # to check bying + stock_codes = { + # 252670 + # 122630 + "252670": ['20220729'], + } + + for stock_code in stock_codes: + stockTrainer = StockTrainer(RESOURCE_PATH) + stockTrainer.train(stock_code) + + + print ("done...") \ No newline at end of file diff --git a/hts/BuySellChecker.py b/hts/BuySellChecker.py index 2e468fb..75971db 100644 --- a/hts/BuySellChecker.py +++ b/hts/BuySellChecker.py @@ -836,6 +836,331 @@ class BuySellChecker: return data + def getSign(self, data1, data2): + diff_sign = [] + for i in range(0, len(data1)): + if data1[i] > data2[i]: diff_sign.append(2) + elif data1[i] == data2[i]: diff_sign.append(1) + else: diff_sign.append(0) + return diff_sign + + def getVectorFeature(self, result): + # 기본 캔들 정보 + open = result["open"] + close = result["close"] + high = result["high"] + low = result["low"] + vol = result["vol"] + label = result["label"] + + # 캔들 정보 연산 + height = [close[i] - open[i] for i in range(0, len(close))] + top_tail_height = [high[i] - max(open[i], close[i]) for i in range(0, len(close))] + bottom_tail_height = [min(open[i], close[i]) - low[i] for i in range(0, len(close))] + diff_price = [close[i] - close[i - 1] for i in range(1, len(close))] + diff_price.insert(0, 0) + diff_price_sign = [] + for i in range(1, len(close)): + if close[i] > close[i - 1]: diff_price_sign.append(2) + elif close[i] == close[i - 1]: diff_price_sign.append(1) + else: diff_price_sign.append(0) + diff_price_sign.insert(0, 0) + + # 이동 평균 + close_df = pd.DataFrame(close) + avg3_list = close_df.rolling(window=3).mean().fillna(close[0]).values.tolist() + avg3 = [item[0] for item in avg3_list] + avg5_list = close_df.rolling(window=5).mean().fillna(close[0]).values.tolist() + avg5 = [item[0] for item in avg5_list] + avg10_list = close_df.rolling(window=10).mean().fillna(close[0]).values.tolist() + avg10 = [item[0] for item in avg10_list] + avg20_list = close_df.rolling(window=20).mean().fillna(close[0]).values.tolist() + avg20 = [item[0] for item in avg20_list] + avg30_list = close_df.rolling(window=30).mean().fillna(close[0]).values.tolist() + avg30 = [item[0] for item in avg30_list] + avg60_list = close_df.rolling(window=60).mean().fillna(close[0]).values.tolist() + avg60 = [item[0] for item in avg60_list] + + abs_avg_1 = [max(avg3[i], avg5[i], avg10[i], avg20[i], avg30[i], avg60[i]) - min(avg3[i], avg5[i], avg10[i], avg20[i], avg30[i], avg60[i]) for i in range(0, len(close))] + abs_avg_2 = [max(avg3[i], avg5[i], avg10[i], avg20[i], avg30[i]) - min(avg3[i], avg5[i], avg10[i], avg20[i], avg30[i]) for i in range(0, len(close))] + abs_avg_3 = [max(avg3[i], avg5[i], avg10[i], avg20[i]) - min(avg3[i], avg5[i], avg10[i], avg20[i]) for i in range(0, len(close))] + abs_avg_4 = [max(avg3[i], avg5[i], avg10[i]) - min(avg3[i], avg5[i], avg10[i]) for i in range(0, len(close))] + abs_avg_5 = [max(avg3[i], avg5[i]) - min(avg3[i], avg5[i]) for i in range(0, len(close))] + diff_avg3_avg5 = [avg3[i]-avg5[i] for i in range(0, len(close))] + diff_avg3_avg10 = [avg3[i] - avg10[i] for i in range(0, len(close))] + diff_avg3_avg20 = [avg3[i] - avg20[i] for i in range(0, len(close))] + diff_avg3_avg30 = [avg3[i] - avg30[i] for i in range(0, len(close))] + diff_avg3_avg60 = [avg3[i] - avg60[i] for i in range(0, len(close))] + diff_avg5_avg10 = [avg5[i] - avg10[i] for i in range(0, len(close))] + diff_avg5_avg20 = [avg5[i] - avg20[i] for i in range(0, len(close))] + diff_avg5_avg30 = [avg5[i] - avg30[i] for i in range(0, len(close))] + diff_avg5_avg60 = [avg5[i] - avg60[i] for i in range(0, len(close))] + diff_avg10_avg20 = [avg10[i] - avg20[i] for i in range(0, len(close))] + diff_avg10_avg30 = [avg10[i] - avg30[i] for i in range(0, len(close))] + diff_avg10_avg60 = [avg10[i] - avg60[i] for i in range(0, len(close))] + diff_avg20_avg30 = [avg20[i] - avg30[i] for i in range(0, len(close))] + diff_avg20_avg60 = [avg20[i] - avg60[i] for i in range(0, len(close))] + diff_avg30_avg60 = [avg30[i] - avg60[i] for i in range(0, len(close))] + diff_avg3_avg5_sign = self.getSign(avg3, avg5) + diff_avg3_avg10_sign = self.getSign(avg3, avg10) + diff_avg3_avg20_sign = self.getSign(avg3, avg20) + diff_avg3_avg30_sign = self.getSign(avg3, avg30) + diff_avg3_avg60_sign = self.getSign(avg3, avg60) + diff_avg5_avg10_sign = self.getSign(avg5, avg10) + diff_avg5_avg20_sign = self.getSign(avg5, avg20) + diff_avg5_avg30_sign = self.getSign(avg5, avg30) + diff_avg5_avg60_sign = self.getSign(avg5, avg60) + diff_avg10_avg20_sign = self.getSign(avg10, avg20) + diff_avg10_avg30_sign = self.getSign(avg10, avg30) + diff_avg10_avg60_sign = self.getSign(avg10, avg60) + diff_avg20_avg30_sign = self.getSign(avg20, avg30) + diff_avg20_avg60_sign = self.getSign(avg20, avg60) + diff_avg30_avg60_sign = self.getSign(avg30, avg60) + + # 볼린져 밴드 + df = pd.DataFrame(close) + max20 = df.rolling(window=20).mean() + stddev20 = df.rolling(window=20).std() + upper_df = max20 + (stddev20 * 2) # 상단 볼린저 밴드 + lower_df = max20 - (stddev20 * 2) # 하단 볼린저 밴드 + + upper, lower = [], [] + for i in range(len(upper_df)): + if i < 10: + upper.append(upper_df.values[0][0]) + lower.append(lower_df.values[0][0]) + else: + upper.append(upper_df.values[i][0]) + lower.append(lower_df.values[i][0]) + + point_temp = result["time"] + STOCK = [] + for i in range(len(open)): + STOCK.append({'volume': vol[i], 'close': close[i], 'open': open[i], 'high': high[i], 'low': low[i], + 'avg3': avg3[i], 'avg5': avg5[i],'avg10': avg10[i],'avg20': avg20[i],'avg30': avg30[i],'avg60': avg60[i]}) + + # stochastic + stochastic_df = self.stochastic.apply(STOCK, n=30, m=5, t=5) + fast_k = stochastic_df['fast_k'].values.tolist() + slow_k = stochastic_df['slow_k'].values.tolist() + slow_d = stochastic_df['slow_d'].values.tolist() + + # macd + macd_df = self.macd.apply(STOCK, short=12, long=26, t=9) + macd = macd_df['macd'].values.tolist() + macds = macd_df['macds'].values.tolist() + macdo = macd_df['macdo'].values.tolist() + + # rsi + rsi_df = self.rsi.apply(STOCK, period=30, window=5) + rsi = rsi_df['rsi'].values.tolist() + rsis = rsi_df['rsis'].values.tolist() + + # ichimokuCloud + ichimokuCloud_df = self.ichimokuCloud.apply(STOCK, c=9, b=26, l=52) + ichimokuCloud_df = ichimokuCloud_df[:len(ichimokuCloud_df) - 51] + changeLine = ichimokuCloud_df['changeLine'].values.tolist() + baseLine = ichimokuCloud_df['baseLine'].values.tolist() + leadingSpan1 = ichimokuCloud_df['leadingSpan1'].values.tolist() + leadingSpan2 = ichimokuCloud_df['leadingSpan2'].values.tolist() + + # 간격 + ##### 볼린져 밴드 + diff_upper_lower = [upper[i] - lower[i] for i in range(0, len(upper))] + diff_open_lower = [open[i] - lower[i] for i in range(0, len(open))] + diff_open_upper = [open[i] - upper[i] for i in range(0, len(open))] + diff_close_lower = [close[i] - lower[i] for i in range(0, len(close))] + diff_close_upper = [close[i] - upper[i] for i in range(0, len(close))] + diff_high_lower = [high[i] - lower[i] for i in range(0, len(high))] + diff_high_upper = [high[i] - upper[i] for i in range(0, len(high))] + diff_low_lower = [low[i] - lower[i] for i in range(0, len(low))] + diff_low_upper = [low[i] - upper[i] for i in range(0, len(low))] + + diff_upper_lower_sign = self.getSign(upper, lower) + diff_open_lower_sign = self.getSign(open, lower) + diff_open_upper_sign = self.getSign(open, upper) + diff_close_lower_sign = self.getSign(close, lower) + diff_close_upper_sign = self.getSign(close, upper) + diff_high_lower_sign = self.getSign(high, lower) + diff_high_upper_sign = self.getSign(high, upper) + diff_low_lower_sign = self.getSign(low, lower) + diff_low_upper_sign = self.getSign(low, upper) + + ##### 일목균형표 + diff_lead1_lead2 = [leadingSpan1[i] - leadingSpan2[i] for i in range(0, len(leadingSpan1))] + diff_change_base = [changeLine[i] - baseLine[i] for i in range(0, len(baseLine))] + diff_base_lead1 = [baseLine[i] - leadingSpan1[i] for i in range(0, len(baseLine))] + diff_base_lead2 = [baseLine[i] - leadingSpan2[i] for i in range(0, len(baseLine))] + diff_change_lead1 = [changeLine[i] - leadingSpan1[i] for i in range(0, len(changeLine))] + diff_change_lead2 = [changeLine[i] - leadingSpan2[i] for i in range(0, len(changeLine))] + diff_open_lead2 = [open[i] - leadingSpan2[i] for i in range(0, len(open))] + diff_open_lead1 = [open[i] - leadingSpan1[i] for i in range(0, len(open))] + diff_open_change = [open[i] - changeLine[i] for i in range(0, len(open))] + diff_open_base = [open[i] - baseLine[i] for i in range(0, len(open))] + diff_close_lead2 = [close[i] - leadingSpan2[i] for i in range(0, len(close))] + diff_close_lead1 = [close[i] - leadingSpan1[i] for i in range(0, len(close))] + diff_close_change = [close[i] - changeLine[i] for i in range(0, len(close))] + diff_close_base = [close[i] - baseLine[i] for i in range(0, len(close))] + diff_high_lead2 = [high[i] - leadingSpan2[i] for i in range(0, len(high))] + diff_high_lead1 = [high[i] - leadingSpan1[i] for i in range(0, len(high))] + diff_high_change = [high[i] - changeLine[i] for i in range(0, len(high))] + diff_high_base = [high[i] - baseLine[i] for i in range(0, len(high))] + diff_low_lead2 = [low[i] - leadingSpan2[i] for i in range(0, len(low))] + diff_low_lead1 = [low[i] - leadingSpan1[i] for i in range(0, len(low))] + diff_low_change = [low[i] - changeLine[i] for i in range(0, len(low))] + diff_low_base = [low[i] - baseLine[i] for i in range(0, len(low))] + diff_macd_macds = [macd[i] - macds[i] for i in range(0, len(macd))] + diff_slowk_slowd = [slow_k[i] - slow_d[i] for i in range(0, len(slow_k))] + diff_rsi_rsis = [rsi[i] - rsis[i] for i in range(0, len(rsi))] + + + diff_lead1_lead2_sign = self.getSign(leadingSpan1, leadingSpan2) + diff_change_base_sign = self.getSign(changeLine, baseLine) + diff_base_lead1_sign = self.getSign(baseLine, leadingSpan1) + diff_base_lead2_sign = self.getSign(baseLine, leadingSpan2) + diff_change_lead1_sign = self.getSign(changeLine, leadingSpan1) + diff_change_lead2_sign = self.getSign(changeLine, leadingSpan2) + diff_open_lead2_sign = self.getSign(open, leadingSpan2) + diff_open_lead1_sign = self.getSign(open, leadingSpan1) + diff_open_change_sign = self.getSign(open, changeLine) + diff_open_base_sign = self.getSign(open, baseLine) + diff_close_lead2_sign = self.getSign(close, leadingSpan2) + diff_close_lead1_sign = self.getSign(close, leadingSpan1) + diff_close_change_sign = self.getSign(close, changeLine) + diff_close_base_sign = self.getSign(close, baseLine) + diff_high_lead2_sign = self.getSign(high, leadingSpan2) + diff_high_lead1_sign = self.getSign(high, leadingSpan1) + diff_high_change_sign = self.getSign(high, changeLine) + diff_high_base_sign = self.getSign(high, baseLine) + diff_low_lead2_sign = self.getSign(low, leadingSpan2) + diff_low_lead1_sign = self.getSign(low, leadingSpan1) + diff_low_change_sign = self.getSign(low, changeLine) + diff_low_base_sign = self.getSign(low, baseLine) + diff_macd_macds_sign = self.getSign(macd, macds) + diff_slowk_slowd_sign = self.getSign(slow_k, slow_d) + diff_rsi_rsis_sign = self.getSign(rsi, rsis) + + # 결과 + temp = { + "date": point_temp, + "open": open, "high": high, "low": low, "close": close, "volume": vol, + "avg3": avg3, "avg5": avg5, "avg10": avg10, "avg20": avg20, "avg30": avg30, "avg60": avg60, + "upper": upper, "lower": lower, + "macd": macd, "macds": macds, "macdo": macdo, + "fast_k": fast_k, "slow_k": slow_k, "slow_d": slow_d, + "rsi": rsi, "rsis": rsis, + "changeLine": changeLine, "baseLine": baseLine, "leadingSpan1": leadingSpan1, "leadingSpan2": leadingSpan2, + "diff_price": diff_price, "height": height, "top_tail_height": top_tail_height, "bottom_tail_height": bottom_tail_height, + "abs_avg_1": abs_avg_1, "abs_avg_2": abs_avg_2, "abs_avg_3": abs_avg_3, "abs_avg_4": abs_avg_4, "abs_avg_5": abs_avg_5, + "diff_avg3_avg5": diff_avg3_avg5, + "diff_avg3_avg10": diff_avg3_avg10, + "diff_avg3_avg20": diff_avg3_avg20, + "diff_avg3_avg30": diff_avg3_avg30, + "diff_avg3_avg60": diff_avg3_avg60, + "diff_avg5_avg10": diff_avg5_avg10, + "diff_avg5_avg20": diff_avg5_avg20, + "diff_avg5_avg30": diff_avg5_avg30, + "diff_avg5_avg60": diff_avg5_avg60, + "diff_avg10_avg20": diff_avg10_avg20, + "diff_avg10_avg30": diff_avg10_avg30, + "diff_avg10_avg60": diff_avg10_avg60, + "diff_avg20_avg30": diff_avg20_avg30, + "diff_avg20_avg60": diff_avg20_avg60, + "diff_avg30_avg60": diff_avg30_avg60, + "diff_upper_lower": diff_upper_lower, + "diff_open_lower": diff_open_lower, + "diff_open_upper": diff_open_upper, + "diff_close_lower": diff_close_lower, + "diff_close_upper": diff_close_upper, + "diff_high_lower": diff_high_lower, + "diff_high_upper": diff_high_upper, + "diff_low_lower": diff_low_lower, + "diff_low_upper": diff_low_upper, + "diff_lead1_lead2": diff_lead1_lead2, + "diff_change_base": diff_change_base, + "diff_base_lead1": diff_base_lead1, + "diff_base_lead2": diff_base_lead2, + "diff_change_lead1": diff_change_lead1, + "diff_change_lead2": diff_change_lead2, + "diff_open_lead2": diff_open_lead2, + "diff_open_lead1": diff_open_lead1, + "diff_open_change": diff_open_change, + "diff_open_base": diff_open_base, + "diff_close_lead2": diff_close_lead2, + "diff_close_lead1": diff_close_lead1, + "diff_close_change": diff_close_change, + "diff_close_base": diff_close_base, + "diff_high_lead2": diff_high_lead2, + "diff_high_lead1": diff_high_lead1, + "diff_high_change": diff_high_change, + "diff_high_base": diff_high_base, + "diff_low_lead2": diff_low_lead2, + "diff_low_lead1": diff_low_lead1, + "diff_low_change": diff_low_change, + "diff_low_base": diff_low_base, + "diff_macd_macds": diff_macd_macds, + "diff_slowk_slowd": diff_slowk_slowd, + "diff_rsi_rsis": diff_rsi_rsis, + "diff_price_sign": diff_price_sign, + "diff_avg3_avg5_sign": diff_avg3_avg5_sign, + "diff_avg3_avg10_sign": diff_avg3_avg10_sign, + "diff_avg3_avg20_sign": diff_avg3_avg20_sign, + "diff_avg3_avg30_sign": diff_avg3_avg30_sign, + "diff_avg3_avg60_sign": diff_avg3_avg60_sign, + "diff_avg5_avg10_sign": diff_avg5_avg10_sign, + "diff_avg5_avg20_sign": diff_avg5_avg20_sign, + "diff_avg5_avg30_sign": diff_avg5_avg30_sign, + "diff_avg5_avg60_sign": diff_avg5_avg60_sign, + "diff_avg10_avg20_sign": diff_avg10_avg20_sign, + "diff_avg10_avg30_sign": diff_avg10_avg30_sign, + "diff_avg10_avg60_sign": diff_avg10_avg60_sign, + "diff_avg20_avg30_sign": diff_avg20_avg30_sign, + "diff_avg20_avg60_sign": diff_avg20_avg60_sign, + "diff_avg30_avg60_sign": diff_avg30_avg60_sign, + "diff_upper_lower_sign": diff_upper_lower_sign, + "diff_open_lower_sign": diff_open_lower_sign, + "diff_open_upper_sign": diff_open_upper_sign, + "diff_close_lower_sign": diff_close_lower_sign, + "diff_close_upper_sign": diff_close_upper_sign, + "diff_high_lower_sign": diff_high_lower_sign, + "diff_high_upper_sign": diff_high_upper_sign, + "diff_low_lower_sign": diff_low_lower_sign, + "diff_low_upper_sign": diff_low_upper_sign, + "diff_lead1_lead2_sign": diff_lead1_lead2_sign, + "diff_change_base_sign": diff_change_base_sign, + "diff_base_lead1_sign": diff_base_lead1_sign, + "diff_base_lead2_sign": diff_base_lead2_sign, + "diff_change_lead1_sign": diff_change_lead1_sign, + "diff_change_lead2_sign": diff_change_lead2_sign, + "diff_open_lead2_sign": diff_open_lead2_sign, + "diff_open_lead1_sign": diff_open_lead1_sign, + "diff_open_change_sign": diff_open_change_sign, + "diff_open_base_sign": diff_open_base_sign, + "diff_close_lead2_sign": diff_close_lead2_sign, + "diff_close_lead1_sign": diff_close_lead1_sign, + "diff_close_change_sign": diff_close_change_sign, + "diff_close_base_sign": diff_close_base_sign, + "diff_high_lead2_sign": diff_high_lead2_sign, + "diff_high_lead1_sign": diff_high_lead1_sign, + "diff_high_change_sign": diff_high_change_sign, + "diff_high_base_sign": diff_high_base_sign, + "diff_low_lead2_sign": diff_low_lead2_sign, + "diff_low_lead1_sign": diff_low_lead1_sign, + "diff_low_change_sign": diff_low_change_sign, + "diff_low_base_sign": diff_low_base_sign, + "diff_macd_macds_sign": diff_macd_macds_sign, + "diff_slowk_slowd_sign": diff_slowk_slowd_sign, + "diff_rsi_rsis_sign": diff_rsi_rsis_sign, + "label": label + } + + data = pd.DataFrame(temp) + df_final_time = pd.DatetimeIndex(point_temp) + data.index = df_final_time + + data = data.fillna(close[0]) + return data + def checkTransaction(self, data, stock_code, type=True): # 4일치 중에서 앞에 2일은 제거한다. date = data['date'].dt.date.unique().tolist() diff --git a/hts/HTS.py b/hts/HTS.py index e6ef69c..121f762 100644 --- a/hts/HTS.py +++ b/hts/HTS.py @@ -553,7 +553,7 @@ class HTS: conn = sqlite3.connect(os.path.join(self.RESOURCE_PATH, "hts.db")) cursor = conn.cursor() - cursor.execute('SELECT ymd, hms, open, high, low, close, volume FROM ' + tableName + ' WHERE CODE=? and ymd=? order by ymd, hms', (stock_code, day,)) + cursor.execute('SELECT ymd, hms, open, high, low, close, volume, label FROM ' + tableName + ' WHERE CODE=? and ymd=? order by ymd, hms', (stock_code, day,)) db_result = cursor.fetchall() for rows in db_result: ymd = rows[0] # hts.날짜 @@ -563,6 +563,7 @@ class HTS: low = rows[4] # hts.저가 close = rows[5] # hts.종가 vol = rows[6] # hts.거래량 + label = 0 if rows[7] is None else rows[7] # hts.매매구분 temp = datetime.strptime(str(ymd) + " " + str(hms).zfill(4) + "00", '%Y%m%d %H%M%S') @@ -572,6 +573,7 @@ class HTS: result["high"].append(int(high)) result["low"].append(int(low)) result["vol"].append(int(vol)) + result["label"].append(int(label)) return @@ -593,7 +595,8 @@ class HTS: "close": [], "high": [], "low": [], - "vol": []} + "vol": [], + "label": []} days = [] for i in range(1, 10): @@ -601,10 +604,10 @@ class HTS: isValid = self.isValidYMD(stock_code, last_day) if isValid: days.append(last_day) - if len(days) >= 3: + if len(days) >= n: break - days.sort() + days = sorted(days) for day in days: self.getDBData(stock_code, day, result) @@ -615,10 +618,11 @@ class HTS: if LAST_DATA is not None: result = copy.deepcopy(LAST_DATA) else: - result = {"check": set(), "time": [], "open": [], "close": [], "high": [], "low": [], "vol": []} + result = {"check": set(), "time": [], "open": [], "close": [], "high": [], "low": [], "vol": [], "label": []} self.getDBData(stock_code, today, result) + int_given_day = int(today) objCpCybos = win32com.client.Dispatch("CpUtil.CpCybos") bConnect = objCpCybos.IsConnect diff --git a/requirements.txt b/requirements.txt index f9ebd18..550dbb1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,5 @@ plotly matplotlib pandas_datareader bs4 -ipywidgets==7.0.0 \ No newline at end of file +ipywidgets==7.0.0 +image-classifiers \ No newline at end of file diff --git a/resources/hts.db b/resources/hts.db index 9e60fbc..a7fd033 100644 Binary files a/resources/hts.db and b/resources/hts.db differ diff --git a/stock/util/DBManager.py b/stock/util/DBManager.py index f2590a9..5fb7564 100644 --- a/stock/util/DBManager.py +++ b/stock/util/DBManager.py @@ -14,10 +14,10 @@ class DBManager: cursor = conn.cursor() # 테이블 생성 - cursor.execute("CREATE TABLE IF NOT EXISTS " + tableName + " (CODE text, NAME text, ymd text, hms text, close REAL, open REAL, high REAL, low REAL, volume REAL, type INTEGER)") + cursor.execute("CREATE TABLE IF NOT EXISTS " + tableName + " (CODE text, NAME text, ymd text, hms text, close REAL, open REAL, high REAL, low REAL, volume REAL, label INTEGER)") # 키 생성 - create_key = "CREATE INDEX IF NOT EXISTS " + tableName + "_idx on " + tableName + " (CODE, ymd, hms, type) " + create_key = "CREATE INDEX IF NOT EXISTS " + tableName + "_idx on " + tableName + " (CODE, ymd, hms, label) " cursor.execute(create_key) conn.commit() diff --git a/stock/util/Stock2Vector.py b/stock/util/Stock2Vector.py index f675c98..55ba8bd 100644 --- a/stock/util/Stock2Vector.py +++ b/stock/util/Stock2Vector.py @@ -1,7 +1,12 @@ import os +import copy import sqlite3 -from datetime import datetime, timedelta +import numpy as np import pandas as pd +from datetime import datetime, timedelta + +from hts.BuySellChecker import BuySellChecker +from hts.HTS import HTS from stock.analysis.Common import Common from stock.analysis.Stochastic import Stochastic @@ -9,7 +14,7 @@ from stock.analysis.RSI import RSI from stock.analysis.MACD import MACD from stock.analysis.IchimokuCloud import IchimokuCloud -class Stock2Vector: +class Stock2Vector(HTS): RESOURCE_PATH = None @@ -20,8 +25,12 @@ class Stock2Vector: ichimokuCloud = None def __init__(self, RESOURCE_PATH): + super().__init__(RESOURCE_PATH) + self.RESOURCE_PATH = RESOURCE_PATH + self.buySellChecker = BuySellChecker() + self.common = Common() self.stochastic = Stochastic() self.rsi = RSI() @@ -110,16 +119,48 @@ class Stock2Vector: df_final_time = pd.DatetimeIndex(point_temp) data.index = df_final_time - data.fillna(0) + data = data.fillna(0) return data - def getDBData(self, stock_code, lastday, result): + def getRealTime(self, stock_code, today, LAST_DATA=None): + if LAST_DATA is not None: + result = copy.deepcopy(LAST_DATA) + else: + result = {"check": set(), "time": [], "open": [], "close": [], "high": [], "low": [], "vol": [], "label": []} + + self.getDBData(stock_code, today, result) + + return result + + def makeData(self, today, stock_code): + LAST_DATA = self.getLastData(stock_code, today) + + result = self.getRealTime(stock_code, today, LAST_DATA) + + # 분석을 통해서 볼린저밴드 상/하단을 계산한다. + df = self.buySellChecker.getVectorFeature(result) + minmax_df1 = (df - df.min()) / (df.max() - df.min()) + minmax_df2 = minmax_df1.drop(["date"], axis="columns") + minmax_df = minmax_df2.join(df['date']) + + # 4일치 중에서 앞에 2일은 제거한다. + date = df['date'].dt.date.unique().tolist() + df = df[df['date'].dt.date != date[0]] + df = df[df['date'].dt.date != date[1]] + minmax_df = minmax_df[minmax_df['date'].dt.date != date[0]] + minmax_df = minmax_df[minmax_df['date'].dt.date != date[1]] + + return df, minmax_df + + def makeTrainData(self, stock_code): + result = {"check": set(), "time": [], "open": [], "close": [], "high": [], "low": [], "vol": [], "label": []} + tableName = 'hts' conn = sqlite3.connect(os.path.join(self.RESOURCE_PATH, "hts.db")) cursor = conn.cursor() - cursor.execute('SELECT ymd, hms, open, high, low, close, volume FROM ' + tableName + ' WHERE CODE=? and ymd=? order by ymd, hms', (stock_code, lastday,)) + cursor.execute('SELECT ymd, hms, open, high, low, close, volume, label FROM ' + tableName + ' WHERE CODE=? order by ymd, hms', (stock_code,)) db_result = cursor.fetchall() for rows in db_result: ymd = rows[0] # hts.날짜 @@ -129,6 +170,7 @@ class Stock2Vector: low = rows[4] # hts.저가 close = rows[5] # hts.종가 vol = rows[6] # hts.거래량 + label = 0 if rows[7] is None else rows[7] # hts.매매구분 temp = datetime.strptime(str(ymd) + " " + str(hms).zfill(4) + "00", '%Y%m%d %H%M%S') @@ -138,46 +180,45 @@ class Stock2Vector: result["high"].append(int(high)) result["low"].append(int(low)) result["vol"].append(int(vol)) - return - - def vectorize(self, stock_code, given_day): - result = {"check": set(), - "time": [], - "open": [], - "close": [], - "high": [], - "low": [], - "vol": []} - - for i in range(1, 10): - last_day = (datetime.strptime(given_day, '%Y%m%d') - timedelta(i)).strftime('%Y%m%d') - self.getDBData(stock_code, last_day, result) - if len(result['time']) > 0: - break - self.getDBData(stock_code, given_day, result) + result["label"].append(int(label)) # 분석을 통해서 볼린저밴드 상/하단을 계산한다. - data = self.analyze(result) + df = self.buySellChecker.getVectorFeature(result) + minmax_df1 = (df - df.min()) / (df.max() - df.min()) + minmax_df2 = minmax_df1.drop(["date"], axis="columns") + minmax_df = minmax_df2.join(df['date']) - return data + minmax_df = minmax_df.fillna(0) + return df, minmax_df + + def vectorize(self, data): + vector = [] + for key in data: + if key == "date": + continue + vector.append(data[key].tolist()) + + return np.asarray(vector) if __name__ == "__main__": PROJECT_HOME = os.path.join(os.path.dirname(os.path.join(os.path.dirname(os.path.join(os.path.dirname(__file__)))))) RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources") - stock2Vector = Stock2Vector(RESOURCE_PATH) - # to check bying stock_codes = { # 252670 # 122630 - "122630": ['20220725'], + "252670": ['20220729'], } for stock_code in stock_codes: + stock2Vector = Stock2Vector(RESOURCE_PATH) for given_day in stock_codes[stock_code]: - stock2Vector.vectorize(stock_code, given_day) + data, minmax_data = stock2Vector.makeData(given_day, stock_code) + vector = stock2Vector.vectorize(data) + minmax_vector = stock2Vector.vectorize(minmax_data) + print (given_day) print ("done...")