diff --git a/HTS_252670_daily.py b/HTS_252670_daily.py index 0f714d1..bbef554 100644 --- a/HTS_252670_daily.py +++ b/HTS_252670_daily.py @@ -62,24 +62,14 @@ class HTS_252670_DAILY (HTS): print ("START...") THIS_TIME = datetime.now() final_sell_check = False - LAST_DATA = self.dailyStatus.getLastData_realtime(self.stock_code, today) + LAST_DATA = self.dailyStatus.getLastData(stock_code, 200) while datetime.strptime(today + " 070000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 153100", '%Y%m%d %H%M%S'): + # 1515 까지만 매수를 시도한다. if datetime.strptime(today + " 090000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 151500", '%Y%m%d %H%M%S'): - # 3시 까지만 매수를 시도한다. - - if THIS_TIME < datetime.strptime(today + " 145000", '%Y%m%d %H%M%S'): - if THIS_TIME.strftime('%S') in ("06", "16", "26", "36", "46", "56"): - # 데이터를 가지고 온다. - result = self.getClosePrice_realtime(self.stock_code, today) - final_price = result["close"][len(result["close"])-1] - - # 10초마다 체크하여 체결된 내역이 있으면 50원 높게 매도를 주문한다. - self.getSellingPrice(THIS_TIME, self.stock_code, final_price, check=True) - + # 매분 3초마다 실행한다. if THIS_TIME.strftime('%S') == "03": - # 매분 3초마다 실행한다. # 데이터를 가지고 온다. result = self.getRealTime(self.stock_code, today, LAST_DATA) diff --git a/Simulation_Daily.py b/Simulation_Daily.py index e515f47..d1739be 100644 --- a/Simulation_Daily.py +++ b/Simulation_Daily.py @@ -1,8 +1,11 @@ import numpy as np from math import nan +import shutil +import sqlite3 import pandas as pd import plotly.graph_objects as go from plotly import subplots +import plotly.io as po import os from datetime import datetime @@ -34,25 +37,6 @@ class Simulation (HTS): buy_weight_line = bsLine['buy_weight'] sell_line = bsLine['sell'] - # 그래프 설정을 위한 변수를 생성한다. - data = data.astype( - { - 'open': 'int', - 'high': 'int', - 'low': 'int', - 'close': 'int', - 'slow_k': 'float', - 'slow_d': 'float', - 'macd': 'float', - 'macds': 'float', - 'envelope_upper': 'float', - 'envelope_lower': 'float', - 'envelope_middle': 'float', - 'rsi': 'float', - 'rsis': 'float' - } - ) - buy_size = [] buy_colors = [] for i in range(len(buy_line)): @@ -62,7 +46,7 @@ class Simulation (HTS): buy_size.append(0) else: buy_colors.append("#B2028C") - buy_size.append(10 + (5 * buy_weight_line[i])) + buy_size.append(10 + (0.1 * buy_weight_line[i])) sell_colors = [] for i in range(len(sell_line)): @@ -79,6 +63,9 @@ class Simulation (HTS): envelope_middle = go.Scatter(x=data['ymd'], y=data["envelope_middle"], name="upper", line_color='#927786') envelope_lower = go.Scatter(x=data['ymd'], y=data["envelope_lower"], name="lower", line_color='#000000') + avg5 = go.Scatter(x=data['ymd'], y=data["avg5"], name="avg5", line_color='#6C2507') + avg20 = go.Scatter(x=data['ymd'], y=data["avg20"], name="avg20", line_color='#f84c43') + avg60 = go.Scatter(x=data['ymd'], y=data["avg60"], name="avg60", line_color='#f89543') candle_stick = go.Candlestick(x=data['ymd'], open=data['open'], high=data['high'], low=data['low'], close=data['close'], increasing_line_color='red', decreasing_line_color='blue', showlegend=False) macd_line = go.Scatter(x=data['ymd'], y=data["macd"], line=dict(color='red', width=2), name='macd') @@ -91,7 +78,12 @@ class Simulation (HTS): rsi_line = go.Scatter(x=data['ymd'], y=data["rsi"], line=dict(color='red', width=2), name='rsi') rsis_line = go.Scatter(x=data['ymd'], y=data["rsis"], line=dict(dash='dashdot', color='black', width=2), name='rsis') - candle_data = [candle_stick, envelope_upper, envelope_middle, envelope_lower, buy_check, sell_check] + disparity_avg5 = go.Scatter(x=data['ymd'], y=data["disparity_avg5"], name="disparity_avg5", line_color='#8F8203') + disparity_avg20 = go.Scatter(x=data['ymd'], y=data["disparity_avg20"], name="disparity_avg20", line_color='#ff00ff') + disparity_avg60 = go.Scatter(x=data['ymd'], y=data["disparity_avg60"], name="disparity_avg60", line_color='#1469F4') + + candle_data = [candle_stick, avg5, avg20, avg60, envelope_upper, envelope_middle, envelope_lower, buy_check, sell_check] + disparity_data = [disparity_avg5, disparity_avg20, disparity_avg60] macd_data = [macd_line, macd_s_line] stochastic_data = [slow_k_line, slow_d_line] rsi_data = [rsi_line, rsis_line] @@ -104,11 +96,11 @@ class Simulation (HTS): """ fig = subplots.make_subplots( - rows=4, cols=1, - subplot_titles=("MACD", "RSI", "스토캐스틱", '캔들'), + rows=5, cols=1, + subplot_titles=("MACD", "RSI", "스토캐스틱", '이격도', '캔들'), #specs=[[{}], [{}], [{}], [{}], [{}], [{}]], shared_xaxes=True, horizontal_spacing=0.03, vertical_spacing=0.01, - row_heights=[200, 200, 200, 750] + row_heights=[200, 200, 200, 200, 750] ) for trace in macd_data: fig.append_trace(trace, 1, 1) @@ -116,8 +108,10 @@ class Simulation (HTS): fig.append_trace(trace, 2, 1) for trace in stochastic_data: fig.append_trace(trace, 3, 1) - for trace in candle_data: + for trace in disparity_data: fig.append_trace(trace, 4, 1) + for trace in candle_data: + fig.append_trace(trace, 5, 1) #fig.update_xaxes(nticks=5) @@ -134,16 +128,241 @@ class Simulation (HTS): return + def writeFile(self, dailyDirName, stock_code, stock_name, given_day, data, bsLine): + if bsLine is None: + return - def simulate(self, stock_code, n=100): - today = datetime.today().strftime('%Y%m%d') - data = self.dailyStatus.getLastData(stock_code, today, n) + # 어제 데이터는 지운다. + buy_line = bsLine['buy'] + buy_weight_line = bsLine['buy_weight'] + sell_line = bsLine['sell'] - # 사야 할 시점과 팔아야 할 시점을 체크한다. - bsLine, data = self.buySellChecker.checkEnvelopeTiming(data, stock_code, isRealTime=False) + buy_size = [] + buy_colors = [] + for i in range(len(buy_line)): + if buy_line[i] < 0: + buy_colors.append("#ffffff") + buy_line[i] = nan + buy_size.append(0) + else: + buy_colors.append("#B2028C") + buy_size.append(10 + (0.1 * buy_weight_line[i])) + + sell_colors = [] + for i in range(len(sell_line)): + if sell_line[i] < 0: + sell_colors.append("#ffffff") + sell_line[i] = nan + else: + sell_colors.append("#00ced1") + + # 그래프를 설정한다. + buy_check = go.Scatter(x=data['ymd'], y=buy_line, mode='markers', name="buy", marker=dict(size=buy_size, color=buy_colors, line_width=0)) + sell_check = go.Scatter(x=data['ymd'], y=sell_line, mode='markers', name="sell", marker=dict(size=14, color=sell_colors, line_width=0)) + envelope_upper = go.Scatter(x=data['ymd'], y=data["envelope_upper"], name="upper", line_color='#000000') + envelope_middle = go.Scatter(x=data['ymd'], y=data["envelope_middle"], name="upper", line_color='#927786') + envelope_lower = go.Scatter(x=data['ymd'], y=data["envelope_lower"], name="lower", line_color='#000000') + + avg5 = go.Scatter(x=data['ymd'], y=data["avg5"], name="avg5", line_color='#6C2507') + avg20 = go.Scatter(x=data['ymd'], y=data["avg20"], name="avg20", line_color='#f84c43') + avg60 = go.Scatter(x=data['ymd'], y=data["avg60"], name="avg60", line_color='#f89543') + candle_stick = go.Candlestick(x=data['ymd'], open=data['open'], high=data['high'], low=data['low'], close=data['close'], increasing_line_color='red', decreasing_line_color='blue', showlegend=False) + + macd_line = go.Scatter(x=data['ymd'], y=data["macd"], line=dict(color='red', width=2), name='macd') + macd_s_line = go.Scatter(x=data['ymd'], y=data["macds"], line=dict(dash='dashdot', color='black', width=2), name='macds') + + # fast_k_line = go.Scatter(x=hts['date'], y=hts["fast_k"], mode='lines', name='fast_k') + slow_k_line = go.Scatter(x=data['ymd'], y=data["slow_k"], line=dict(color='red', width=2), name='slow_k') + slow_d_line = go.Scatter(x=data['ymd'], y=data["slow_d"], line=dict(dash='dashdot', color='black', width=2), name='slow_d') + + rsi_line = go.Scatter(x=data['ymd'], y=data["rsi"], line=dict(color='red', width=2), name='rsi') + rsis_line = go.Scatter(x=data['ymd'], y=data["rsis"], line=dict(dash='dashdot', color='black', width=2), name='rsis') + + disparity_avg5 = go.Scatter(x=data['ymd'], y=data["disparity_avg5"], name="disparity_avg5", line_color='#8F8203') + disparity_avg20 = go.Scatter(x=data['ymd'], y=data["disparity_avg20"], name="disparity_avg20", line_color='#ff00ff') + disparity_avg60 = go.Scatter(x=data['ymd'], y=data["disparity_avg60"], name="disparity_avg60", line_color='#1469F4') + + candle_data = [candle_stick, avg5, avg20, avg60, envelope_upper, envelope_middle, envelope_lower, buy_check, sell_check] + disparity_data = [disparity_avg5, disparity_avg20, disparity_avg60] + macd_data = [macd_line, macd_s_line] + stochastic_data = [slow_k_line, slow_d_line] + rsi_data = [rsi_line, rsis_line] # 그래프를 그린다. - self.draw(stock_code, today, data, bsLine) + """ + fig = go.Figure(data=candle_data) + fig.update_layout(title=stock_code + "_" + given_day) + fig.show() + """ + + fig = subplots.make_subplots( + rows=5, cols=1, + subplot_titles=("MACD", "RSI", "스토캐스틱", '이격도', '캔들'), + #specs=[[{}], [{}], [{}], [{}], [{}], [{}]], + shared_xaxes=True, horizontal_spacing=0.03, vertical_spacing=0.01, + row_heights=[200, 200, 200, 200, 750] + ) + for trace in macd_data: + fig.append_trace(trace, 1, 1) + for trace in rsi_data: + fig.append_trace(trace, 2, 1) + for trace in stochastic_data: + fig.append_trace(trace, 3, 1) + for trace in disparity_data: + fig.append_trace(trace, 4, 1) + for trace in candle_data: + fig.append_trace(trace, 5, 1) + + + #fig.update_xaxes(nticks=5) + #fig.update_layout(height=1800, title=stock_code + "_" + given_day, xaxis_rangeslider_visible=False) + + df = pd.DataFrame(bsLine) + df = df.fillna(-1) + buy_count = len(df.loc[df["buy"] > 0]) + sell_count = len(df.loc[df["sell"] > 0]) + + fig.update_layout(height=1700, title=stock_code + "_" + given_day + "_" + str(buy_count)+","+str(sell_count)) + #fig.update_layout(title=stock_code + "_" + given_day + "_" + str(buy_count) + "," + str(sell_count)) + #fig.show() + + fileName = "%s/%s_%s.html" % (dailyDirName, stock_code, stock_name.replace(" ", "")) + po.write_html(fig, file=fileName, auto_open=False) + + return + + def getData(self, today, stock): + close = stock['PRICE'][len(stock['PRICE']) - 1]["close"] + open = stock['PRICE'][len(stock['PRICE']) - 1]["open"] + high = stock['PRICE'][len(stock['PRICE']) - 1]["high"] + low = stock['PRICE'][len(stock['PRICE']) - 1]["low"] + volume = stock['PRICE'][len(stock['PRICE']) - 1]["volume"] + + stock['PRICE'].append( + { + "ymd": today, + "close": close, + "diff": stock['PRICE'][len(stock['PRICE']) - 1]["close"] - close, + "open": open, + "high": high, + "low": low, + "volume": volume, + "avg3": -1, + "avg4": -1, + "avg5": -1, + "avg6": -1, + "avg10": -1, + "avg12": -1, + "avg20": -1, + "avg36": -1, + "avg40": -1, + "avg48": -1, + "avg60": -1, + "avg120": -1, + "avg200": -1, + "avg240": -1, + "avg300": -1, + "disparity_avg5": -1, + "disparity_avg10": -1, + "disparity_avg20": -1, + "disparity_avg60": -1, + "disparity_avg120": -1, + "bolingerband_upper": -1, + "bolingerband_lower": -1, + "bolingerband_middle": -1, + "envelope_upper": -1, + "envelope_lower": -1, + "envelope_middle": -1, + "ichimokucloud_changeLine": -1, + "ichimokucloud_baseLine": -1, + "ichimokucloud_leadingSpan1": -1, + "ichimokucloud_leadingSpan2": -1, + "stochastic_fast_k": -1, + "stochastic_slow_k": -1, + "stochastic_slow_d": -1, + "rsi": -1, + "rsis": -1, + "macd": -1, + "macds": -1, + "macdo": -1, + } + ) + + return + + def simulate(self, stock_code=None, isRealTime=False): + if not isRealTime: + n = 200 + else: + n = 200 + + if stock_code is not None: + stock = self.dailyStatus.getLastData(stock_code, n) + + today = datetime.today().strftime('%Y%m%d') + self.getData(today, stock) + analyzed_day = 60 + data = self.dailyStatus.analyze(stock, analyzed_day) + # 분석일 데이터만 활용한다 (이전 데이터는 제거) + data.drop(data.index[:analyzed_day], inplace=True) + + # print logs + for i in range(len(data.index)): + print (i, data.index[i], data['macd'][i], data['slow_k'][i], data['gradients_low'][i], data['gradients_avg5'][i], data['gradients_avg20'][i], data['gradients_avg60'][i], data['disparity_avg5'][i], data['disparity_avg20'][i], data['disparity_avg60'][i], data['disparity'][i], data['disparity_type'][i]) + + bsLine, data = self.buySellChecker.checkTransactionWithEnvelope(data, stock_code, isRealTime=False) + + # 그래프를 그린다. + self.draw(stock_code, today, data, bsLine) + else: + stockTableName = 'stock' + PROJECT_HOME = os.path.join(os.path.dirname(__file__)) + stockFileName = PROJECT_HOME + '/resources/stock.db' + + conn = sqlite3.connect(stockFileName) + cursor = conn.cursor() + cursor.execute('SELECT distinct code, name FROM ' + stockTableName + ' order by code') + items = cursor.fetchall() + cursor.close() + conn.close() + + today = datetime.today().strftime('%Y%m%d') + dailyDirName = os.path.join(RESOURCE_PATH, 'analysis', today, 'daily') + if os.path.exists(dailyDirName): + shutil.rmtree(dailyDirName) + + dailyDirName = os.path.join(RESOURCE_PATH, 'analysis', today) + if not os.path.isdir(dailyDirName): + os.mkdir(dailyDirName) + dailyDirName = os.path.join(dailyDirName, 'daily') + if not os.path.isdir(dailyDirName): + os.mkdir(dailyDirName) + + for idx, item in enumerate(items): + stock_code = item[0] + stock_name = item[1] + print(idx, stock_code, stock_name) + print("Analysis # :", idx, ", CODE: ", stock_code, ", NAME: ", stock_name) + + stock = self.dailyStatus.getLastData(stock_code, n) + + today = datetime.today().strftime('%Y%m%d') + self.getData(today, stock) + analyzed_day = 60 + data = self.dailyStatus.analyze(stock, analyzed_day) + # 분석일 데이터만 활용한다 (이전 데이터는 제거) + data.drop(data.index[:analyzed_day], inplace=True) + + # print logs + # for i in range(len(data.index)): + # print (i, data.index[i], data['macd'][i], data['slow_k'][i], data['gradients_low'][i], data['gradients_avg5'][i], data['gradients_avg20'][i], data['gradients_avg60'][i], data['disparity_avg5'][i], data['disparity_avg20'][i], data['disparity_avg60'][i], data['disparity'][i], data['disparity_type'][i]) + + bsLine, data = self.buySellChecker.checkTransactionWithEnvelope(data, stock_code, isRealTime=False) + + # 그래프를 그린다. + + if len(data.index) > 10 and max(bsLine['buy'][len(bsLine['buy'])-2:]) > 0: + self.writeFile(dailyDirName, stock_code, stock_name, today, data, bsLine) return @@ -152,13 +371,18 @@ if __name__ == "__main__": PROJECT_HOME = os.getcwd() RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources") - # to check bying - stock_codes = ["252670", "122630"] - #stock_codes = ["252670"] - #stock_codes = ["122630"] + simulation = Simulation(RESOURCE_PATH) + # to check buying + #stock_codes = ["252670", "122630"] + #stock_codes = ["051600", "139130", "066570", "000990"] + stock_codes = ["102950"] + + """ for stock_code in stock_codes: - simulation = Simulation(RESOURCE_PATH) - simulation.simulate(stock_code, 2000) + simulation.simulate(stock_code) + """ + simulation.simulate() print ("done...") + diff --git a/StockCrawler.py b/StockCrawler.py index 58644a3..779b34b 100644 --- a/StockCrawler.py +++ b/StockCrawler.py @@ -54,13 +54,13 @@ if week in (0, 1, 2, 3, 4): # 0:월, 1:화, 2:수, 3:목, 4:금, 5:토, 6:일 print("\n[종목 분석]") # S: 분석까지 진행 inFileName = PROJECT_HOME + '/resources/stock.db' - analyzerSqlite = AnalyzerSqlite(PROJECT_HOME, stockFileName) + analyzerSqlite = AnalyzerSqlite(stockFileName) analyzerSqlite.analyzeDaily() analyzerSqlite.analyzeGrouping("weekly") analyzerSqlite.analyzeGrouping("monthly") - analyzerSqlite = AnalyzerSqlite(PROJECT_HOME, stockFileName) + analyzerSqlite = AnalyzerSqlite(stockFileName) print("\n[종목 결정]") # HTML 출력 outPath = os.path.join(PROJECT_HOME, "resources", "analysis") diff --git a/hts/BuySellChecker.py b/hts/BuySellChecker.py index 526fdf6..8b46b8a 100644 --- a/hts/BuySellChecker.py +++ b/hts/BuySellChecker.py @@ -1,4 +1,5 @@ import pandas as pd + from stock.analysis.Common import Common from stock.analysis.Stochastic import Stochastic from stock.analysis.RSI import RSI @@ -6,7 +7,6 @@ from stock.analysis.MACD import MACD from stock.analysis.IchimokuCloud import IchimokuCloud class BuySellChecker: - common = None stochastic = None rsi = None @@ -23,8 +23,8 @@ class BuySellChecker: self.ichimokuCloud = IchimokuCloud() self.BUY_COUNT = 0 - return + return def isYangbong(self, data, i): if data['close'][i] > data['open'][i]: @@ -67,23 +67,28 @@ class BuySellChecker: check_under_20_for_10 = False for c in range(i - within, i - during): - value = [1 if max(data['avg3'][d], data['avg6'][d], data['avg9'][d], data['avg12'][d]) < data['avg20'][d] else 0 for d in range(c, c + during)] + value = [ + 1 if max(data['avg3'][d], data['avg6'][d], data['avg9'][d], data['avg12'][d]) < data['avg20'][d] else 0 + for d in range(c, c + during)] if len(value) == during and sum(value) == during: check_under_20_for_10 = True break return check_under_20_for_10 def max_min_avg(self, data, i): - return max(data['avg3'][i], data['avg6'][i], data['avg9'][i], data['avg12'][i], data['avg20'][i]) - min(data['avg3'][i], data['avg6'][i], data['avg9'][i], data['avg12'][i], data['avg20'][i]) + return max(data['avg3'][i], data['avg6'][i], data['avg9'][i], data['avg12'][i], data['avg20'][i]) - min( + data['avg3'][i], data['avg6'][i], data['avg9'][i], data['avg12'][i], data['avg20'][i]) def check_inverse_arrangement_before(self, data, i, within=30, during=5): if i - within < 381: return False inverse_arrangement = False - for c in range(i-within, i-during): - value = [1 if data['avg3'][d] < data['avg6'][d] < data['avg9'][d] < data['avg12'][d] < data['avg20'][d] else 0 for d in range(c, c + during)] - if len(value) == during and sum(value) == during-1: + for c in range(i - within, i - during): + value = [ + 1 if data['avg3'][d] < data['avg6'][d] < data['avg9'][d] < data['avg12'][d] < data['avg20'][d] else 0 + for d in range(c, c + during)] + if len(value) == during and sum(value) == during - 1: inverse_arrangement = True break return inverse_arrangement @@ -91,15 +96,15 @@ class BuySellChecker: def checkUpDirection(self, data, i): # 0: 무추세, -1: 하락 추세, 1: 상승 추세 close = data['close'][i] - #up_count = sum([1 if data['high'][c] < close else 0 for c in range(i-20, i)]) - #down_count = sum([1 if close < data['low'][c] else 0 for c in range(i - 20, i)]) + # up_count = sum([1 if data['high'][c] < close else 0 for c in range(i-20, i)]) + # down_count = sum([1 if close < data['low'][c] else 0 for c in range(i - 20, i)]) - lagging_change = sum([1 if data['laggingSpan'][c] < data['changeLine'][c] else 0 for c in range(i-20, i)]) - change_lagging = sum([1 if data['laggingSpan'][c] > data['changeLine'][c] else 0 for c in range(i-20, i)]) + lagging_change = sum([1 if data['laggingSpan'][c] < data['changeLine'][c] else 0 for c in range(i - 20, i)]) + change_lagging = sum([1 if data['laggingSpan'][c] > data['changeLine'][c] else 0 for c in range(i - 20, i)]) - if lagging_change>10: + if lagging_change > 10: return 1 - if change_lagging==20: + if change_lagging == 20: return -1 return 0 @@ -159,8 +164,10 @@ class BuySellChecker: if i > START_TIME_INDEX: # 매도 분석 - if data['changeLine'][i - 1] >= data['laggingSpan'][i - 1] and data['laggingSpan'][i] < data['changeLine'][i]: - changeLine_count = sum([1 if data['changeLine'][c] <= data['laggingSpan'][c] else 0 for c in range(i - 20, i)]) + if data['changeLine'][i - 1] >= data['laggingSpan'][i - 1] and data['laggingSpan'][i] < data['changeLine'][ + i]: + changeLine_count = sum( + [1 if data['changeLine'][c] <= data['laggingSpan'][c] else 0 for c in range(i - 20, i)]) if changeLine_count >= 17: sell = min(data["open"][i], data["close"][i]) weight = 1 @@ -225,8 +232,10 @@ class BuySellChecker: if i > START_TIME_INDEX: # 매도 분석 - if data['changeLine'][i - 1] >= data['laggingSpan'][i - 1] and data['laggingSpan'][i] < data['changeLine'][i]: - changeLine_count = sum([1 if data['changeLine'][c] <= data['laggingSpan'][c] else 0 for c in range(i - 20, i)]) + if data['changeLine'][i - 1] >= data['laggingSpan'][i - 1] and data['laggingSpan'][i] < data['changeLine'][ + i]: + changeLine_count = sum( + [1 if data['changeLine'][c] <= data['laggingSpan'][c] else 0 for c in range(i - 20, i)]) if changeLine_count >= 17: sell = min(data["open"][i], data["close"][i]) weight = 1 @@ -273,8 +282,8 @@ class BuySellChecker: 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_df = max20 + (stddev20 * 2) # 상단 볼린저 밴드 + lower_df = max20 - (stddev20 * 2) # 하단 볼린저 밴드 upper, lower = [], [] for i in range(len(upper_df)): @@ -321,13 +330,15 @@ class BuySellChecker: temp = { "date": point_temp, "open": open, "high": high, "low": low, "close": close, "volume": vol, - "avg3": avg3,"avg6": avg6,"avg9": avg9,"avg12": avg12, "avg20": avg20, - "disparity_avg5": disparity_avg5, "disparity_avg10": disparity_avg10, "disparity_avg20": disparity_avg20, "disparity_avg60": disparity_avg60, "disparity_avg120": disparity_avg120, + "avg3": avg3, "avg6": avg6, "avg9": avg9, "avg12": avg12, "avg20": avg20, + "disparity_avg5": disparity_avg5, "disparity_avg10": disparity_avg10, "disparity_avg20": disparity_avg20, + "disparity_avg60": disparity_avg60, "disparity_avg120": disparity_avg120, "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, "laggingSpan": laggingSpan, "leadingSpan1": leadingSpan1, "leadingSpan2": leadingSpan2, + "changeLine": changeLine, "baseLine": baseLine, "laggingSpan": laggingSpan, "leadingSpan1": leadingSpan1, + "leadingSpan2": leadingSpan2, "label": label } @@ -368,9 +379,15 @@ class BuySellChecker: avg54_list = close_df.rolling(window=54).mean().fillna(close[0]).values.tolist() avg54 = [item[0] for item in avg54_list] - abs_avg_1 = [max(avg3[i], avg6[i], avg9[i], avg12[i], avg27[i], avg54[i]) - min(avg3[i], avg6[i], avg9[i], avg12[i], avg27[i], avg54[i]) for i in range(0, len(close))] - abs_avg_2 = [max(avg3[i], avg6[i], avg9[i], avg12[i], avg27[i]) - min(avg3[i], avg6[i], avg9[i], avg12[i], avg27[i]) for i in range(0, len(close))] - abs_avg_3 = [max(avg3[i], avg6[i], avg9[i], avg12[i]) - min(avg3[i], avg6[i], avg9[i], avg12[i]) for i in range(0, len(close))] + abs_avg_1 = [ + max(avg3[i], avg6[i], avg9[i], avg12[i], avg27[i], avg54[i]) - min(avg3[i], avg6[i], avg9[i], avg12[i], + avg27[i], avg54[i]) for i in + range(0, len(close))] + abs_avg_2 = [ + max(avg3[i], avg6[i], avg9[i], avg12[i], avg27[i]) - min(avg3[i], avg6[i], avg9[i], avg12[i], avg27[i]) for + i in range(0, len(close))] + abs_avg_3 = [max(avg3[i], avg6[i], avg9[i], avg12[i]) - min(avg3[i], avg6[i], avg9[i], avg12[i]) for i in + range(0, len(close))] abs_avg_4 = [max(avg3[i], avg6[i], avg9[i]) - min(avg3[i], avg6[i], avg9[i]) for i in range(0, len(close))] abs_avg_5 = [max(avg3[i], avg6[i]) - min(avg3[i], avg6[i]) for i in range(0, len(close))] @@ -391,7 +408,7 @@ class BuySellChecker: diff_avg3, diff_avg6, diff_avg9, diff_avg12, diff_avg27, diff_avg54 = [], [], [], [], [], [] diff_avg3.append(0) for i in range(1, len(avg3)): - diff_avg3.append(avg3[i]-avg3[i-1]) + diff_avg3.append(avg3[i] - avg3[i - 1]) diff_avg6.append(0) for i in range(1, len(avg6)): diff_avg6.append(avg6[i] - avg6[i - 1]) @@ -408,7 +425,6 @@ class BuySellChecker: for i in range(1, len(avg54)): diff_avg54.append(avg54[i] - avg54[i - 1]) - diff_avg3_avg6 = [avg3[i] - avg6[i] for i in range(0, len(close))] diff_avg3_avg9 = [avg3[i] - avg9[i] for i in range(0, len(close))] diff_avg3_avg12 = [avg3[i] - avg12[i] for i in range(0, len(close))] @@ -429,8 +445,8 @@ class BuySellChecker: 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_df = max20 + (stddev20 * 2) # 상단 볼린저 밴드 + lower_df = max20 - (stddev20 * 2) # 하단 볼린저 밴드 upper, lower = [], [] for i in range(len(upper_df)): @@ -445,7 +461,8 @@ class BuySellChecker: 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], 'avg6': avg6[i],'avg9': avg9[i],'avg12': avg12[i],'avg27': avg27[i],'avg54': avg54[i]}) + 'avg3': avg3[i], 'avg6': avg6[i], 'avg9': avg9[i], 'avg12': avg12[i], 'avg27': avg27[i], + 'avg54': avg54[i]}) # stochastic stochastic_df = self.stochastic.apply(STOCK, n=30, m=5, t=5) @@ -484,7 +501,6 @@ class BuySellChecker: 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_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))] @@ -512,7 +528,6 @@ class BuySellChecker: 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_macd, diff_macdo, diff_macds = [], [], [] diff_macd.append(0) for i in range(1, len(macd)): @@ -570,14 +585,16 @@ class BuySellChecker: "rsi": rsi, "rsis": rsis, "changeLine": changeLine, "baseLine": baseLine, "leadingSpan1": leadingSpan1, "leadingSpan2": leadingSpan2, "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, + "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_open": diff_open, "diff_close": diff_close, "diff_low": diff_low, "diff_high": diff_high, - "diff_avg3":diff_avg3, "diff_avg6":diff_avg6, "diff_avg9":diff_avg9, "diff_avg12":diff_avg12, "diff_avg27":diff_avg27, "diff_avg54":diff_avg54, - "diff_macd":diff_macd, "diff_macdo":diff_macdo, "diff_macds":diff_macds, - "diff_fast_k":diff_fast_k, "diff_slow_k":diff_slow_k, "diff_slow_d":diff_slow_d, - "diff_rsi":diff_rsi, "diff_rsis":diff_rsis, - "diff_changeLine":diff_changeLine, "diff_baseLine":diff_baseLine, - "diff_upper":diff_upper, "diff_lower":diff_lower, + "diff_avg3": diff_avg3, "diff_avg6": diff_avg6, "diff_avg9": diff_avg9, "diff_avg12": diff_avg12, + "diff_avg27": diff_avg27, "diff_avg54": diff_avg54, + "diff_macd": diff_macd, "diff_macdo": diff_macdo, "diff_macds": diff_macds, + "diff_fast_k": diff_fast_k, "diff_slow_k": diff_slow_k, "diff_slow_d": diff_slow_d, + "diff_rsi": diff_rsi, "diff_rsis": diff_rsis, + "diff_changeLine": diff_changeLine, "diff_baseLine": diff_baseLine, + "diff_upper": diff_upper, "diff_lower": diff_lower, "diff_avg3_avg6": diff_avg3_avg6, "diff_avg3_avg9": diff_avg3_avg9, "diff_avg3_avg12": diff_avg3_avg12, @@ -790,7 +807,6 @@ class BuySellChecker: return bsLine, data - def checkTransactionML(self, data, stock_code, predY, isRealTime=True): # 4일치 중에서 앞에 2일은 제거한다. date = data['date'].dt.date.unique().tolist() @@ -841,88 +857,68 @@ class BuySellChecker: + # middle line에 맞다은 적 없이, low line에 붙었거나 아래에 있었던 캔들의 높은 가격을 얻어옴 + def getPrice_UnderLowWithoutMiddle(self, last_index, data): + if data['high'][last_index] < data['envelope_middle'][last_index]: + for i in range(last_index - 1, 0, -1): + if data['high'][i] > data['envelope_middle'][i]: + return -1, -1 + if data['low'][i] < data['envelope_lower'][i]: + return i, max(data['open'][i], data['close'][i]) + return -1, -1 - def getBuyPriceAndWeight_Envelope_trend(self, data, i): - buy, weight, type = -1, -1, -1 + def getBuyPriceAndWeight_Envelope(self, i, data): + buy, weight = -1, -1 - if data['close'][i-1] < data['envelope_lower'][i-1] and data['envelope_lower'][i] < data['close'][i]: - buy = data["close"][i] - weight = 1 - type = 1 + """ + # middle line에 맞다은 적 없이, low line에 붙었거나 아래에 있었던 캔들의 높은 가격을 얻어옴 + index, price = self.getPrice_UnderLowWithoutMiddle(i, data) + if price > -1: + # 해당 가격보다 높은 가격이면 매수한다 + if price < data['close'][i]: + buy = data['close'][i] + weight = 10 + """ + if i > 100: + if -0.004 < data['gradient1'][i] < 0.001: + #if data['high'][i] < data['envelope_middle'][i]: + if data['slow_k'][i] < 20: + buy = data['close'][i] + weight = 10 - if data['close'][i] < data['envelope_lower'][i]: - if data['rsis'][i] < data['rsi'][i]: - buy = data["close"][i] - weight = 1 - type = 2 + """ + if i > 100: + if min(data['gradient1'][i-5:i]) < -0.009 and -0.009 < data['gradient1'][i]: + if data['high'][i] < data['envelope_middle'][i]: + buy = data['close'][i] + weight = 10 + """ + return buy, weight - if data['close'][i-1] < data['envelope_middle'][i-1] and data['envelope_middle'][i] < data['close'][i]: - if data['slow_k'][i] < 25: - buy = data["close"][i] - weight = 1 - type = 3 - - check1 = False - check2 = False - if data['slow_k'][i] < 40: - if data['close'][i-1] < data['envelope_middle'][i-1] and data['envelope_middle'][i] < data['close'][i]: - idx = -1 - for t1 in range(i-1, i-10, -1): - if data['close'][t1] < data['envelope_middle'][t1]: - check1 = True - idx = t1 - break - if check1: - for t1 in range(idx-1, i - 10, -1): - if data['envelope_middle'][t1] < data['close'][t1]: - check2 = True - break - if check2: - buy = data["close"][i] - weight = 1 - type = 4 - - if data.index[i].strftime("%Y.%m.%d") == "2021.12.21": - print(1) - - check = True - if data['slow_k'][i] < 40: - if data['close'][i - 1] < data['envelope_middle'][i - 1] and data['envelope_middle'][i] < data['close'][i]: - - for t1 in range(i-1, i-10, -1): - if data['envelope_middle'][t1] < data['close'][t1]: - check = False - if check: - buy = data["close"][i] - weight = 1 - type = 4 - - return buy, weight, type - - def getSellPriceAndWeight_Envelope_trend(self, data, i): + def getSellPriceAndWeight_Envelope(self, data, i): sell, weight, type = -1, -1, -1 if data.index[i].strftime("%Y.%m.%d") == "2022.12.01": - print (1) + print(1) # upper lined에서 처리 - if data['close'][i-1] < data['envelope_upper'][i - 1] and data['envelope_upper'][i] < data['close'][i]: - if data['slow_d'][i-1] <= data['slow_k'][i - 1] and data['slow_k'][i] <= data['slow_d'][i]: + if data['close'][i - 1] < data['envelope_upper'][i - 1] and data['envelope_upper'][i] < data['close'][i]: + if data['slow_d'][i - 1] <= data['slow_k'][i - 1] and data['slow_k'][i] <= data['slow_d'][i]: sell = data["close"][i] weight = 1 type = 1 - if data['envelope_upper'][i-1] < data['close'][i - 1] and data['envelope_upper'][i] < data['close'][i]: - if data['slow_d'][i-1] <= data['slow_k'][i - 1] and data['slow_k'][i] <= data['slow_d'][i]: + if data['envelope_upper'][i - 1] < data['close'][i - 1] and data['envelope_upper'][i] < data['close'][i]: + if data['slow_d'][i - 1] <= data['slow_k'][i - 1] and data['slow_k'][i] <= data['slow_d'][i]: sell = data["close"][i] weight = 1 type = 2 - if data['envelope_upper'][i-1] < data['close'][i - 1] and data['envelope_upper'][i] < data['close'][i]: - if data['slow_d'][i-1] +2 <= data['slow_k'][i - 1] and data['slow_d'][i]+1 == data['slow_k'][i]: + if data['envelope_upper'][i - 1] < data['close'][i - 1] and data['envelope_upper'][i] < data['close'][i]: + if data['slow_d'][i - 1] + 2 <= data['slow_k'][i - 1] and data['slow_d'][i] + 1 == data['slow_k'][i]: sell = data["close"][i] weight = 1 type = 3 - if data['envelope_upper'][i] 5: + return True + return - if data['close'][i-1] < data['envelope_lower'][i-1] and data['envelope_lower'][i] < data['close'][i]: - buy = data["close"][i] - weight = 1 - type = 1 + def checkWithEnvelope_252670(self, data, isRealTime=False): - if data['close'][i] < data['envelope_lower'][i]: - if data['rsis'][i] < data['rsi'][i]: - buy = data["close"][i] - weight = 1 - type = 2 - - return buy, weight, type - - def getSellPriceAndWeight_Envelope(self, data, i): - sell, weight, type = -1, -1, -1 - - if data.index[i].strftime("%Y.%m.%d") == "2022.12.01": - print (1) - - # upper lined에서 처리 - if data['close'][i-1] < data['envelope_upper'][i - 1] and data['envelope_upper'][i] < data['close'][i]: - if data['slow_d'][i-1] <= data['slow_k'][i - 1] and data['slow_k'][i] <= data['slow_d'][i]: - sell = data["close"][i] - weight = 1 - type = 1 - if data['envelope_upper'][i-1] < data['close'][i - 1] and data['envelope_upper'][i] < data['close'][i]: - if data['slow_d'][i-1] <= data['slow_k'][i - 1] and data['slow_k'][i] <= data['slow_d'][i]: - sell = data["close"][i] - weight = 1 - type = 2 - if data['envelope_upper'][i-1] < data['close'][i - 1] and data['envelope_upper'][i] < data['close'][i]: - if data['slow_d'][i-1] +2 <= data['slow_k'][i - 1] and data['slow_d'][i]+1 == data['slow_k'][i]: - sell = data["close"][i] - weight = 1 - type = 3 - - # middle lined에서 처리 - middle_up = False - if data['envelope_middle'][i-1] < data['close'][i-1] or data['envelope_middle'][i] < data['open'][i]: - if data['envelope_middle'][i-2] < data['close'][i-2] or data['envelope_middle'][i-1] < data['close'][i-1] or data['envelope_middle'][i] < data['close'][i]: - for t in range(i-1, i-20, -1): - if data['envelope_upper'][t] <= data['close'][t]: - middle_up = False - break - if data['close'][t] < data['envelope_middle'][t]: - middle_up = True - break - - if middle_up: - if data['slow_d'][i-1] < data['slow_k'][i-1] and data['slow_k'][i] < data['slow_d'][i]: - sell = data["close"][i] - weight = 1 - type = 4 - - - return sell, weight, type - - def checkEnvelopeTiming(self, data, stock_code, isRealTime=True): - # 어제 오늘 데이터로 분석 bsLine = {} size = len(data["close"]) - if isRealTime: - # isRealTime=True, 실시간 적용 - last_index = size - 1 + bsLine['buy'] = [-1 for i in range(size)] + bsLine['buy_weight'] = [-1 for i in range(size)] + bsLine['sell'] = [-1 for i in range(size)] + bsLine['sell_weight'] = [-1 for i in range(size)] - if stock_code == "252670": - buy, buy_weight, buy_type = self.getBuyPriceAndWeight_Envelope(data, last_index) - sell, sell_weight, sell_type = self.getSellPriceAndWeight_Envelope(data, last_index) - else: - buy, buy_weight, buy_type = self.getBuyPriceAndWeight_Envelope(data, last_index) - sell, sell_weight, sell_type = self.getSellPriceAndWeight_Envelope(data, last_index) + for i in range(size): + if isRealTime: + if i < size - 1: + continue - bsLine['buy'] = [buy] - bsLine['buy_weight'] = [buy_weight] - bsLine['sell'] = [sell] - bsLine['sell_weight'] = [sell_weight] + """ + # 이전에 산 가격보다 지금 5원이상 떨어졌다면 매도 한다. + price = data['close'][i] if data['close'][i] >= data['open'][i] else data['open'][i] + if self.checkBelow5WonFromPreviousBuyPrice(i, data, price): + data['sell'][i] = price + bsLine['sell'][i] = price + bsLine['sell_weight'][i] = 50 + return bsLine, data + """ - else: - # Type=False, 시뮬레이션 적용 - bsLine['buy'] = [-1 for i in range(size)] - bsLine['buy_weight'] = [-1 for i in range(size)] - bsLine['sell'] = [-1 for i in range(size)] - bsLine['sell_weight'] = [-1 for i in range(size)] + """ + # middle line에 맞다은 적 없이, low line에 붙었거나 아래에 있었던 캔들의 높은 가격을 얻어옴 + buy, buy_weight = self.getBuyPriceAndWeight_Envelope(i, data) + data['buy'][i] = buy + bsLine['buy'][i] = buy + bsLine['buy_weight'][i] = buy_weight + return bsLine, data + """ - for i in range(size): - if stock_code == "252670": - buy, buy_weight, buy_type = self.getBuyPriceAndWeight_Envelope_trend(data, i) - sell, sell_weight, sell_type = self.getSellPriceAndWeight_Envelope_trend(data, i) - else: - buy, buy_weight, buy_type = self.getBuyPriceAndWeight_Envelope(data, i) - sell, sell_weight, sell_type = self.getSellPriceAndWeight_Envelope(data, i) - bsLine['buy'][i] = buy - bsLine['buy_weight'][i] = buy_weight - bsLine['sell'][i] = sell - bsLine['sell_weight'][i] = sell_weight - if i > 0: - if bsLine['sell'][i-1] > -1: - bsLine['sell'][i] = -1 - bsLine['sell_weight'][i] = -1 + if 0 < data['gradients_avg60'][i] < 0.001: + if data['high'][i] < data['envelope_middle'][i]: + if -0.015 < data['gradients_avg5'][i] and -0.007 < data['gradients_avg20'][i]: + buy = data['low'][i] + data['buy'][i] = buy + bsLine['buy'][i] = buy + bsLine['buy_weight'][i] = 10 + + if i > 10: + if ( + data['gradients_avg60'][i - 10] > 0 and data['gradients_avg60'][i - 9] > 0 and data['gradients_avg60'][i - 8] > 0 and + data['gradients_avg60'][i - 7] > 0 and data['gradients_avg60'][i - 6] > 0 and data['gradients_avg60'][i - 5] > 0 and + data['gradients_avg60'][i - 4] > 0 and data['gradients_avg60'][i - 3] > 0 and data['gradients_avg60'][i - 2] > 0 and + data['gradients_avg60'][i - 1] > 0 and data['gradients_avg60'][i] < 0 + ): + if data['disparity'][i] < 3: + buy = data['low'][i] + data['buy'][i] = buy + bsLine['buy'][i] = buy + bsLine['buy_weight'][i] = 10 + + if i > 10: + if data['disparity_avg60'][i] < 65: + buy = data['low'][i] + data['buy'][i] = buy + bsLine['buy'][i] = buy + bsLine['buy_weight'][i] = 20 + + if data['slow_k'][i] < 3: + buy = data['low'][i] + data['buy'][i] = buy + bsLine['buy'][i] = buy + bsLine['buy_weight'][i] = 10 return bsLine, data + + + def checkWithEnvelope_122630(self, data, isRealTime=False): + + bsLine = {} + size = len(data["close"]) + + bsLine['buy'] = [-1 for i in range(size)] + bsLine['buy_weight'] = [-1 for i in range(size)] + bsLine['sell'] = [-1 for i in range(size)] + bsLine['sell_weight'] = [-1 for i in range(size)] + + for i in range(size): + if isRealTime: + if i < size - 1: + continue + + if i > 10: + if data['disparity_avg60'][i] < 60: + buy = data['low'][i] + data['buy'][i] = buy + bsLine['buy'][i] = buy + bsLine['buy_weight'][i] = 20 + + if data['macd'][i] < -1000: + buy = data['low'][i] + data['buy'][i] = buy + bsLine['buy'][i] = buy + bsLine['buy_weight'][i] = 20 + + if data['slow_k'][i] < 7: + if data['slow_d'][i] < data['slow_k'][i]: + buy = data['low'][i] + data['buy'][i] = buy + bsLine['buy'][i] = buy + bsLine['buy_weight'][i] = 5 + + return bsLine, data + + def notBuy(self, data, i): + if i > 5: + check = True + for l in range(i-4, i+1): + if ( + data['gradients_avg60'][l - 1] > data['gradients_avg60'][l] or + data['gradients_avg20'][l - 1] > data['gradients_avg20'][l] or + data['gradients_low'][l - 1] > data['gradients_low'][l] + ): + check = False + break + if not check: + return False + return True + + def checkWithEnvelope(self, data, isRealTime=False): + + bsLine = {} + size = len(data["close"]) + + bsLine['buy'] = [-1 for i in range(size)] + bsLine['buy_weight'] = [-1 for i in range(size)] + bsLine['sell'] = [-1 for i in range(size)] + bsLine['sell_weight'] = [-1 for i in range(size)] + + for i in range(size): + if isRealTime: + if i < size - 1: + continue + + if i > 10: + if data['disparity'][i] < 2: + check = True + for l in range(i-3, i): + if ( + data['gradients_avg60'][l-1] > data['gradients_avg60'][l] or + data['gradients_avg20'][l-1] > data['gradients_avg20'][l] or + data['gradients_low'][l-1] > data['gradients_low'][l] or + data['disparity_avg5'][l-1] > data['disparity_avg5'][l] or + data['disparity'][l-1] < data['disparity'][l] + ): + check = False + break + if check and 99 < sum(data['disparity_avg5'][i-4:i+1])/5 < 100 and 99 < sum(data['disparity_avg60'][i-4:i+1])/5 < 100: + buy = data['low'][i] + data['buy'][i] = buy + bsLine['buy'][i] = buy + bsLine['buy_weight'][i] = 20 + + check = True + for l in range(i - 2, i): + if ( + data['gradients_avg60'][l - 1] > data['gradients_avg60'][l] or + data['gradients_low'][l - 1] > data['gradients_low'][l] + ): + check = False + break + if ( + check and + -0.0011 < data['gradients_low'][i] < 0 and -0.007 < data['gradients_avg5'][i] < 0.001 and + -0.0012 < data['gradients_avg60'][i] < 0 and + 98.90 < data['disparity_avg5'][i] < 101 + ): + buy = data['low'][i] + data['buy'][i] = buy + bsLine['buy'][i] = buy + bsLine['buy_weight'][i] = 20 + + check = True + for l in range(i - 6, i): + if ( + data['gradients_avg60'][l - 1] < data['gradients_avg60'][l] or + data['gradients_avg20'][l - 1] < data['gradients_avg20'][l] or + data['gradients_low'][l - 1] < data['gradients_low'][l] or + -0.039 < data['gradients_low'][l - 1] < -0.35 or + -0.05 < data['gradients_avg20'][l - 1] < -0.30 or + -0.40 < data['gradients_avg60'][l - 1] < -0.30 + ): + check = False + break + if check and 99 < min (data['disparity_avg5'][i - 6:i]) < max (data['disparity_avg5'][i - 6:i]) < 101: + buy = data['low'][i] + data['buy'][i] = buy + bsLine['buy'][i] = buy + bsLine['buy_weight'][i] = 20 + + check = True + for l in range(i - 3, i): + if ( + data['gradients_low'][l - 1] < data['gradients_low'][l] or + data['gradients_avg60'][l - 1] < data['gradients_avg60'][l] or + data['gradients_avg20'][l - 1] < data['gradients_avg20'][l] or + 0.01 < data['gradients_low'][l - 1] < 0.21 or + -0.09 < data['gradients_avg20'][l - 1] < -0.002 or + 0.01 < data['gradients_avg60'][l - 1] < 0.021 + ): + check = False + break + if check: + buy = data['low'][i] + data['buy'][i] = buy + bsLine['buy'][i] = buy + bsLine['buy_weight'][i] = 20 + + + if (data['disparity'][i] < 5 and 99.0 < data['disparity_avg60'][i] < 99.1 and + -0.009 < data['gradients_avg60'][i] < -0.008 and 0.015 < data['gradients_avg20'][i] < 0.016 and + -0.006 < data['gradients_avg5'][i] < -0.005 and -0.009 < data['gradients_low'][i] < -0.008): + check = True + for l in range(i-5, i): + if ( + data['gradients_avg60'][l-1] > data['gradients_avg60'][l] or + data['gradients_low'][l-1] > data['gradients_low'][l] or + data['disparity'][l - 1] < data['disparity'][l] + ): + check = False + break + if check: + buy = data['low'][i] + data['buy'][i] = buy + bsLine['buy'][i] = buy + bsLine['buy_weight'][i] = 20 + + if data['macd'][i] < -4000: + if data['macd'][i-1] < data['macd'][i]: + if not self.notBuy(data, i) and data['slow_k'][i] < 30: + buy = data['low'][i] + data['buy'][i] = buy + bsLine['buy'][i] = buy + bsLine['buy_weight'][i] = 20 + + # macd 이전에 없던 바닥인 경우 상승할 찰나 매수 + if data['macds'][i-1] < min(data['macds'][:i-1]): + if data['macds'][i-1] < data['macds'][i]: + if not self.notBuy(data, i) and data['slow_k'][i] < 30: + buy = data['low'][i] + data['buy'][i] = buy + bsLine['buy'][i] = buy + bsLine['buy_weight'][i] = 20 + + if ( + 98 < data['disparity_avg5'][i] < 100 and data['disparity_avg20'][i] < 93.5 and data['disparity_avg60'][i] < 89 and + -0.014 < data['gradients_avg60'][i] < -0.013 and -0.03 < data['gradients_avg20'][i] < -0.02 and -0.014 < data['gradients_low'][i] < -0.013 and + data['slow_k'][i] < 11 + ): + if not self.notBuy(data, i): + buy = data['low'][i] + data['buy'][i] = buy + bsLine['buy'][i] = buy + bsLine['buy_weight'][i] = 20 + + + """ + if data['disparity_avg60'][i] < 60: + buy = data['low'][i] + data['buy'][i] = buy + bsLine['buy'][i] = buy + bsLine['buy_weight'][i] = 20 + """ + + return bsLine, data + + def checkTransactionWithEnvelope(self, data, stock_code, isRealTime=False): + if isRealTime: + if stock_code == "252670": + bsLine, data = self.checkWithEnvelope_252670(data, isRealTime) + elif stock_code == "122630": + bsLine, data = self.checkWithEnvelope_122630(data, isRealTime) + else: + bsLine, data = self.checkWithEnvelope(data, isRealTime) + else: + # 사야 할 시점과 팔아야 할 시점을 체크한다. + if stock_code == "252670": + bsLine, data = self.checkWithEnvelope_252670(data, isRealTime) + elif stock_code == "122630": + bsLine, data = self.checkWithEnvelope_122630(data, isRealTime) + else: + bsLine, data = self.checkWithEnvelope(data, isRealTime) + + return bsLine, data \ No newline at end of file diff --git a/hts/DailyStatus.py b/hts/DailyStatus.py index 98064f5..4966c1a 100644 --- a/hts/DailyStatus.py +++ b/hts/DailyStatus.py @@ -5,17 +5,21 @@ if platform.system().lower().find("window") >= 0 and platform.architecture()[0] import win32com.client import sqlite3 -from datetime import datetime, timedelta +from sklearn.linear_model import LinearRegression +from sklearn.preprocessing import StandardScaler, MinMaxScaler +from stock.analysis.AnalyzerSqlite import AnalyzerSqlite class DailyStatus: tableName = None dbFileName = None RESOURCE_PATH = None + analyzerSqlite = None def __init__(self, RESOURCE_PATH): self.RESOURCE_PATH = RESOURCE_PATH - self.tableName = 'stock_analysis' + self.tableName = 'stock' self.dbFileName = "stock.db" + self.analyzerSqlite = AnalyzerSqlite(os.path.join(self.RESOURCE_PATH, self.dbFileName)) return def getDBData(self, stock_code, day, result): @@ -67,13 +71,118 @@ class DailyStatus: return True return False - def getLastData(self, stock_code, today, n=100): + def getLastData(self, stock_code, limit=350): + stockTableName = 'stock' + + conn = sqlite3.connect(os.path.join(self.RESOURCE_PATH, self.dbFileName)) + cursor = conn.cursor() + + stock = {"CODE": stock_code, "NAME": "", "PRICE": []} + + sql = 'SELECT ymd, close, diff, open, high, low, volume FROM ' + stockTableName + ' where CODE=? order by ymd desc ' + sql += ' limit ' + str(limit) + cursor.execute(sql, (stock['CODE'],)) + items = cursor.fetchall() + + items_reverse = reversed(items) + for item in items_reverse: + stock['PRICE'].append( + { + "ymd": item[0], + "close": item[1], + "diff": item[2], + "open": item[3], + "high": item[4], + "low": item[5], + "volume": item[6], + "avg3": -1, + "avg4": -1, + "avg5": -1, + "avg6": -1, + "avg10": -1, + "avg12": -1, + "avg20": -1, + "avg36": -1, + "avg40": -1, + "avg48": -1, + "avg60": -1, + "avg120": -1, + "avg200": -1, + "avg240": -1, + "avg300": -1, + "disparity_avg5": -1, + "disparity_avg10": -1, + "disparity_avg20": -1, + "disparity_avg60": -1, + "disparity_avg120": -1, + "bolingerband_upper": -1, + "bolingerband_lower": -1, + "bolingerband_middle": -1, + "envelope_upper": -1, + "envelope_lower": -1, + "envelope_middle": -1, + "ichimokucloud_changeLine": -1, + "ichimokucloud_baseLine": -1, + "ichimokucloud_leadingSpan1": -1, + "ichimokucloud_leadingSpan2": -1, + "stochastic_fast_k": -1, + "stochastic_slow_k": -1, + "stochastic_slow_d": -1, + "rsi": -1, + "rsis": -1, + "macd": -1, + "macds": -1, + "macdo": -1, + } + ) + + conn.commit() + cursor.close() + conn.close() + + return stock + + def analyze (self, stock, days=120): + stock["PRICE"] = sorted(stock["PRICE"], key=lambda x: x['ymd']) + self.analyzerSqlite.get_moving_average(stock["PRICE"]) + + # 이동 평균을 이용한 이격도 계산 + self.analyzerSqlite.get_disparity(stock["PRICE"]) + + self.analyzerSqlite.ichimokuCloud.analyze(stock) + self.analyzerSqlite.stochastic.analyze(stock) + self.analyzerSqlite.bolingerBand.analyze(stock) + self.analyzerSqlite.envelope.analyze(stock) + self.analyzerSqlite.rsi.analyze(stock) + self.analyzerSqlite.macd.analyze(stock) + result = { "ymd": [], "open": [], "close": [], "high": [], "low": [], + "avg3": [], + "avg4": [], + "avg5": [], + "avg6": [], + "avg10": [], + "avg12": [], + "avg20": [], + "avg36": [], + "avg40": [], + "avg48": [], + "avg60": [], + "avg120": [], + "avg200": [], + "avg240": [], + "avg300": [], + "disparity_avg5": [], + "disparity_avg20": [], + "disparity_avg60": [], + "disparity_avg120": [], + "disparity": [], + "disparity_type": [], "envelope_upper": [], "envelope_lower": [], "envelope_middle": [], @@ -82,58 +191,166 @@ class DailyStatus: "macd": [], "macds": [], "slow_k": [], - "slow_d": [] + "slow_d": [], + "buy": [], + "sell": [], } - - days = [] - for i in range(1, n): - last_day = (datetime.strptime(today, '%Y%m%d') - timedelta(i)).strftime('%Y.%m.%d') - isValid = self.isValidYMD(stock_code, last_day) - if isValid: - days.append(last_day) - - days = sorted(days) - for day in days: - self.getDBData(stock_code, day, result) + for item in stock['PRICE']: + result["ymd"].append(item['ymd']) + result["open"].append(item['open']) + result["close"].append(item['close']) + result["high"].append(item['high']) + result["low"].append(item['low']) + result["avg3"].append(item['avg3']) + result["avg4"].append(item['avg4']) + result["avg5"].append(item['avg5']) + result["avg6"].append(item['avg6']) + result["avg10"].append(item['avg10']) + result["avg12"].append(item['avg12']) + result["avg20"].append(item['avg20']) + result["avg36"].append(item['avg36']) + result["avg40"].append(item['avg40']) + result["avg48"].append(item['avg48']) + result["avg60"].append(item['avg60']) + result["avg120"].append(item['avg120']) + result["avg200"].append(item['avg200']) + result["avg240"].append(item['avg240']) + result["avg300"].append(item['avg300']) + result["disparity_avg5"].append(item['disparity_avg5']) + result["disparity_avg20"].append(item['disparity_avg20']) + result["disparity_avg60"].append(item['disparity_avg60']) + result["disparity_avg120"].append(item['disparity_avg120']) + result['disparity'].append(max(item['disparity_avg5'], item['disparity_avg20'], item['disparity_avg60']) - min(item['disparity_avg5'], item['disparity_avg20'], item['disparity_avg60'])) + if item['disparity_avg60'] < item['disparity_avg20'] < item['disparity_avg5']: + result['disparity_type'].append(1) + elif item['disparity_avg5'] < item['disparity_avg20'] < item['disparity_avg60']: + result['disparity_type'].append(-1) + else: + result['disparity_type'].append(0) + result["envelope_upper"].append(item['envelope_upper']) + result["envelope_lower"].append(item['envelope_lower']) + result["envelope_middle"].append(item['envelope_middle']) + result["rsi"].append(item['rsi']) + result["rsis"].append(item['rsis']) + result["macd"].append(item['macd']) + result["macds"].append(item['macds']) + result["slow_k"].append(item['stochastic_slow_k']) + result["slow_d"].append(item['stochastic_slow_d']) + result["buy"].append(-1) + result["sell"].append(-1) data = pd.DataFrame(result) df_final_time = pd.DatetimeIndex(result['ymd']) data.index = df_final_time + data = data.astype( + { + 'open': 'int', + 'high': 'int', + 'low': 'int', + 'close': 'int', + 'avg3': 'float', + 'avg4': 'float', + 'avg5': 'float', + 'avg6': 'float', + 'avg10': 'float', + 'avg12': 'float', + 'avg20': 'float', + 'avg36': 'float', + 'avg40': 'float', + 'avg48': 'float', + 'avg60': 'float', + 'avg120': 'float', + 'avg200': 'float', + 'avg240': 'float', + 'avg300': 'float', + 'disparity_avg5': 'float', + 'disparity_avg20': 'float', + 'disparity_avg60': 'float', + 'disparity_avg120': 'float', + 'buy': 'int', + 'sell': 'int', + 'slow_k': 'float', + 'slow_d': 'float', + 'macd': 'float', + 'macds': 'float', + 'envelope_upper': 'float', + 'envelope_lower': 'float', + 'envelope_middle': 'float', + 'rsi': 'float', + 'rsis': 'float' + } + ) + + scaler = StandardScaler() + low_df = pd.DataFrame(data['low']) + low_df.index = [c for c in range(len(low_df))] + low_std = scaler.fit_transform(data['low'].values.reshape(-1, 1)) + low_std = pd.DataFrame(low_std, columns=['low_std']) + + min_df = pd.DataFrame({'open': data['open'].to_list(), 'close': data['close'].to_list()}) + min_df['min_std'] = min_df.min(axis=1) + min_df.index = [c for c in range(len(min_df))] + min_std = scaler.fit_transform(min_df['min_std'].values.reshape(-1, 1)) + min_std = pd.DataFrame(min_std, columns=['min_std']) + + line_fitter = LinearRegression() + size = len(data["close"]) + gradients_low = [] + gradients_avg5 = [] + gradients_avg20 = [] + gradients_avg60 = [] + + for i in range(size): + coef_low = -999 + coef_avg5 = -999 + coef_avg20 = -999 + coef_avg60 = -999 + + if i > 0: + l = days if i >= days else i + x = pd.DataFrame([c for c in range(i - l, i + 1)]) + y = pd.DataFrame(low_std.values.tolist()[i - l:i + 1]) + line_fitter.fit(x.values.reshape(-1, 1), y) + coef_low = line_fitter.coef_[0][0] + + l = 5 if i >= 5 else i + x = pd.DataFrame([c for c in range(i - l, i + 1)]) + y = pd.DataFrame(min_std.values.tolist()[i - l:i + 1]) + line_fitter.fit(x.values.reshape(-1, 1), y) + coef_avg5 = line_fitter.coef_[0][0] + + l = 20 if i >= 20 else i + x = pd.DataFrame([c for c in range(i - l, i + 1)]) + y = pd.DataFrame(min_std.values.tolist()[i - l:i + 1]) + line_fitter.fit(x.values.reshape(-1, 1), y) + coef_avg20 = line_fitter.coef_[0][0] + + l = 60 if i >= 60 else i + x = pd.DataFrame([c for c in range(i - l, i + 1)]) + y = pd.DataFrame(min_std.values.tolist()[i - l:i + 1]) + line_fitter.fit(x.values.reshape(-1, 1), y) + coef_avg60 = line_fitter.coef_[0][0] + + gradients_low.append(coef_low) + gradients_avg5.append(coef_avg5) + gradients_avg20.append(coef_avg20) + gradients_avg60.append(coef_avg60) + + gradients_low_df = pd.DataFrame(gradients_low, columns=['gradients_low']) + gradients_avg5_df = pd.DataFrame(gradients_avg5, columns=['gradients_avg5']) + gradients_avg20_df = pd.DataFrame(gradients_avg20, columns=['gradients_avg20']) + gradients_avg60_df = pd.DataFrame(gradients_avg60, columns=['gradients_avg60']) + + gradients_low_df.index = df_final_time + gradients_avg5_df.index = df_final_time + gradients_avg20_df.index = df_final_time + gradients_avg60_df.index = df_final_time + + data = data.merge(gradients_low_df, left_index=True, right_index=True) + data = data.merge(gradients_avg5_df, left_index=True, right_index=True) + data = data.merge(gradients_avg20_df, left_index=True, right_index=True) + data = data.merge(gradients_avg60_df, left_index=True, right_index=True) + return data - - def getLastData_realtime(self, stock_code, today, n=100): - result = { - "ymd": [], - "open": [], - "close": [], - "high": [], - "low": [], - "envelope_upper": [], - "envelope_lower": [], - "envelope_middle": [], - "rsi": [], - "rsis": [], - "macd": [], - "macds": [], - "slow_k": [], - "slow_d": [] - } - - days = [] - for i in range(1, n): - last_day = (datetime.strptime(today, '%Y%m%d') - timedelta(i)).strftime('%Y.%m.%d') - isValid = self.isValidYMD(stock_code, last_day) - if isValid: - days.append(last_day) - - days = sorted(days) - for day in days: - self.getDBData(stock_code, day, result) - - data = pd.DataFrame(result) - df_final_time = pd.DatetimeIndex(result['ymd']) - data.index = df_final_time - - return data \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index e199fcc..ecb04b9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,5 +14,4 @@ ipywidgets==7.0.0 torchvision transformers -sklearn -finterstellar +scikit-learn \ No newline at end of file diff --git a/stock/analysis/AnalyzerSqlite.py b/stock/analysis/AnalyzerSqlite.py index 4d93034..935678a 100644 --- a/stock/analysis/AnalyzerSqlite.py +++ b/stock/analysis/AnalyzerSqlite.py @@ -8,7 +8,6 @@ from datetime import datetime from dateutil.relativedelta import relativedelta from matplotlib import rc import pandas as pd -import copy rc('font', family='AppleGothic') plt.rcParams['axes.unicode_minus'] = False @@ -27,8 +26,6 @@ from stock.analysis.Envelope import Envelope from stock.crawler.MovingAverage import MovingAverage class AnalyzerSqlite: - PROJECT_HOME = None - stochastic = None bolingerBand = None ichimokuCloud = None @@ -45,8 +42,7 @@ class AnalyzerSqlite: moving_avg = None - def __init__(self, PROJECT_HOME, stockFileName): - self.PROJECT_HOME = PROJECT_HOME + def __init__(self, stockFileName): self.stockFileName = stockFileName self.common = Common() @@ -1032,7 +1028,7 @@ if __name__ == "__main__": PROJECT_HOME = os.path.join(os.path.dirname(os.path.join(os.path.dirname(os.path.join(os.path.dirname(__file__)))))) stockFileName = PROJECT_HOME + '/resources/stock.db' - analyzer = AnalyzerSqlite(PROJECT_HOME, stockFileName) + analyzer = AnalyzerSqlite(stockFileName) #analyzer.analyzeDaily() #analyzer.analyzeGrouping("weekly")