From bcac177c61b20b8d6194b4faa425a771e381af49 Mon Sep 17 00:00:00 2001 From: dsyoon Date: Mon, 26 Apr 2021 00:46:47 +0900 Subject: [PATCH] init --- stockpredictor/analysis/Analyzer.py | 299 ++++++++------------- stockpredictor/analysis/Common.py | 199 +++++++------- stockpredictor/crawler/toSQLite/Crawler.py | 5 +- 3 files changed, 210 insertions(+), 293 deletions(-) diff --git a/stockpredictor/analysis/Analyzer.py b/stockpredictor/analysis/Analyzer.py index 2e7cc49..0766e7c 100644 --- a/stockpredictor/analysis/Analyzer.py +++ b/stockpredictor/analysis/Analyzer.py @@ -3,17 +3,13 @@ import os import time import shutil from stockpredictor.analysis.Common import Common -from stockpredictor.analysis.MACD import MACD -from stockpredictor.analysis.RSI import RSI from stockpredictor.analysis.Stochastic import Stochastic -from stockpredictor.analysis.IchimokuCloud import IchimokuCloud import matplotlib.pyplot as plt import datetime import sqlite3 from datetime import datetime from matplotlib import rc -import math rc('font', family='AppleGothic') plt.rcParams['axes.unicode_minus'] = False @@ -30,10 +26,7 @@ class Analyzer: stocks = None candidate = None - macd = None - rsi = None stochastic = None - ichimokuCloud = None common = None inFileName = None @@ -51,10 +44,7 @@ class Analyzer: self.common = Common() - self.macd = MACD() - self.rsi = RSI() self.stochastic = Stochastic() - self.ichimokuCloud = IchimokuCloud() self.readFnguide() return @@ -97,57 +87,29 @@ class Analyzer: if last_index > 300: index = 300 # 최대 300일치 그래프 확인 df_stock = pd.DataFrame(stock["PRICE"][len(stock["PRICE"]) - index:]) - df_macd = pd.DataFrame(stock["MACD"][len(stock["MACD"]) - index:last_index+1]) df_stochastic = pd.DataFrame(stock["STOCHASTIC"][len(stock["STOCHASTIC"]) - index:last_index+1]) - df_rsi = pd.DataFrame(stock["RSI"][len(stock["RSI"]) - index:last_index+1]) - df_ichimoku = pd.DataFrame(stock["ICHIMOKU"][len(stock["ICHIMOKU"]) - index:]) else: index = last_index df_stock = pd.DataFrame(stock["PRICE"][:index+1]) - df_macd = pd.DataFrame(stock["MACD"][:index+1]) df_stochastic = pd.DataFrame(stock["STOCHASTIC"][:index+1]) - df_ichimoku = pd.DataFrame(stock["ICHIMOKU"][:index+1]) - df_rsi = pd.DataFrame(stock["RSI"][:index+1]) # general volume = go.Bar(x=df_stock.DATE, y=df_stock['volume'], name="volume") volume_data = [volume] - leadingSpan1 = go.Scatter(x=df_ichimoku.DATE, y=df_ichimoku['leadingSpan1'], name="선행스팬", line_color='#8B4513') - leadingSpan2 = go.Scatter(x=df_ichimoku.DATE, y=df_ichimoku['leadingSpan2'], name="후행스팬", line_color='#4169E1') - cnadle = go.Candlestick(x=df_stock.DATE, open=df_stock.open, high=df_stock.high, low=df_stock.low, close=df_stock.close, increasing_line_color= 'red', decreasing_line_color= 'blue') - ichimokuCloud_data = [leadingSpan1, leadingSpan2, cnadle] - - # macd - macd = go.Scatter(x=df_macd.DATE, y=df_macd['macd'], name="MACD", line_color='#8B4513') - macd_signal = go.Scatter(x=df_macd.DATE, y=df_macd['macds'], name="MACD Signal", line_color='#4169E1') - oscillator = go.Bar(x=df_macd.DATE, y=df_macd['macdo'], name="oscillator") - macd_data = [macd, macd_signal, oscillator] - # stochastic slow_k = go.Scatter(x=df_stochastic.DATE, y=df_stochastic['slow_k'], name="Slow%K", line_color='#8B4513') slow_d = go.Scatter(x=df_stochastic.DATE, y=df_stochastic['slow_d'], name="Slow%D", line_color='#4169E1') stochastic_data = [slow_k, slow_d] - # rsi - rsi = go.Scatter(x=df_macd.DATE, y=df_rsi['rsi'], name="RSI", line_color='#8B4513') - rsi_signal = go.Scatter(x=df_macd.DATE, y=df_rsi['rsis'], name="RSI Signal", line_color='#4169E1') - rsi_data = [rsi, rsi_signal] + fig = subplots.make_subplots(rows=2, cols=1, subplot_titles=('거래량', 'Stochastic')) - fig = subplots.make_subplots(rows=5, cols=1, subplot_titles=('MACD', 'Stochastic', 'RSI', '거래량', '일목균형표')) - - for trace in macd_data: + for trace in volume_data: fig.append_trace(trace, 1, 1) for trace in stochastic_data: fig.append_trace(trace, 2, 1) - for trace in rsi_data: - fig.append_trace(trace, 3, 1) - for trace in volume_data: - fig.append_trace(trace, 4, 1) - for trace in ichimokuCloud_data: - fig.append_trace(trace, 5, 1) - fig.update_layout(height=2000) + fig.update_layout(height=800) return fig @@ -157,63 +119,6 @@ class Analyzer: return i-1 return len(stock['PRICE']) - 1 - def analyzeMACD(self): - conn = sqlite3.connect(self.inFileName) - cursor = conn.cursor() - - # 기존 분석 데이터를 모두 지움 - cursor.execute('update ' + self.tableName + ' set MACD = ""') - - rowid = 1 - cursor.execute('SELECT * FROM ' + self.tableName + ' WHERE rowid=?', (rowid,)) - result = cursor.fetchone() - while result != None: - stock = {"CODE": result[0], "NAME": result[1], "PRICE": json.loads(result[2])} - results = self.macd.analyze(stock) - text = json.dumps(results, ensure_ascii=False) - cursor.execute("UPDATE " + self.tableName + " SET MACD=? WHERE CODE=?", (text, stock["CODE"])) - - print("#analyzeMACD", rowid, stock['NAME']) - rowid += 1 - cursor.execute('SELECT * FROM ' + self.tableName + ' WHERE rowid=?', (rowid,)) - result = cursor.fetchone() - - conn.commit() - cursor.close() - conn.close() - - return - - def analyzeRSI(self): - conn = sqlite3.connect(self.inFileName) - cursor = conn.cursor() - - # 기존 분석 데이터를 모두 지움 - cursor.execute('update ' + self.tableName + ' set RSI = ""') - - rowid = 1 - cursor.execute('SELECT * FROM ' + self.tableName + ' WHERE rowid=?', (rowid,)) - result = cursor.fetchone() - while result != None: - prices = json.loads(result[2]) - for price in prices: - del price['diff'] - stock = {"CODE": result[0], "NAME": result[1], "PRICE": prices} - results = self.rsi.analyze(stock) - text = json.dumps(results, ensure_ascii=False) - cursor.execute("UPDATE " + self.tableName + " SET RSI=? WHERE CODE=?", (text, stock["CODE"])) - - print("#analyzeRSI", rowid, stock['NAME']) - rowid += 1 - cursor.execute('SELECT * FROM ' + self.tableName + ' WHERE rowid=?', (rowid,)) - result = cursor.fetchone() - - conn.commit() - cursor.close() - conn.close() - - return - def analyzeStochastic(self): conn = sqlite3.connect(self.inFileName) cursor = conn.cursor() @@ -240,33 +145,7 @@ class Analyzer: conn.close() return - def analyzeIchimokuCloud(self): - conn = sqlite3.connect(self.inFileName) - cursor = conn.cursor() - - # 기존 분석 데이터를 모두 지움 - cursor.execute('update ' + self.tableName + ' set ICHIMOKU = ""') - - rowid = 1 - cursor.execute('SELECT * FROM ' + self.tableName + ' WHERE rowid=?', (rowid,)) - result = cursor.fetchone() - while result != None: - stock = {"CODE": result[0], "NAME": result[1], "PRICE": json.loads(result[2])} - results = self.ichimokuCloud.analyze(stock) - text = json.dumps(results, ensure_ascii=False) - cursor.execute("UPDATE " + self.tableName + " SET ICHIMOKU=? WHERE CODE=?", (text, stock["CODE"])) - - print("#analyzeIchimokuCloud", rowid, stock['NAME']) - rowid += 1 - cursor.execute('SELECT * FROM ' + self.tableName + ' WHERE rowid=?', (rowid,)) - result = cursor.fetchone() - - conn.commit() - cursor.close() - conn.close() - return - - def analyzeFinalScore(self, last_index, STOCK, MACD, STOCHASTIC, ICHIMOKU, RSI): + def analyzeFinalScore(self, last_index, STOCK, STOCHASTIC): """ 매수 조건 #0. 최소 매수 조건은 거래량은 20만건, 종가는 2천원 이상인 종목이어야 한다. @@ -290,40 +169,69 @@ class Analyzer: if STOCK[i]['volume'] > 100000 and STOCK[i]['close'] > 2000: # 거래량이 100만 이상이고, 종가가 1천원 이상인지 체크 (https://happpy-rich.tistory.com/94) - # 5-20 - days20_line_buying1_status = self.common.check_days5_20_line_buying(STOCK, i) - if days20_line_buying1_status != "": + # 정배열 체크 + temp_status = self.common.check_RightArrange(STOCK, i) + if temp_status != "": #if STOCHASTIC[i]['slow_k'] < 40: - status += days20_line_buying1_status + status += temp_status - # 5-60 - days60_line_buying1_status = self.common.check_days5_60_line_buying(STOCK, i) - if days60_line_buying1_status != "": - # if STOCHASTIC[i]['slow_k'] < 40: - status += days60_line_buying1_status - - # 5-120 - days120_line_buying1_status = self.common.check_days5_120_line_buying(STOCK, i) - if days120_line_buying1_status != "": - # if STOCHASTIC[i]['slow_k'] < 40: - status += days120_line_buying1_status - - # 5-240 - days240_line_buying1_status = self.common.check_days5_240_line_buying(STOCK, i) - if days240_line_buying1_status != "": - # if STOCHASTIC[i]['slow_k'] < 40: - status += days240_line_buying1_status - - # 20-60 - days60_line_buying2_status = self.common.check_days20_60_line_buying(STOCK, i) - if days60_line_buying2_status != "": + # 20 + temp_status = self.common.check_Dolpa_Jiji(STOCK, i, '20') + if temp_status != "": #if STOCHASTIC[i]['slow_k'] < 40: - status += days60_line_buying2_status + status += temp_status + + # 60 + temp_status = self.common.check_Dolpa_Jiji(STOCK, i, '60') + if temp_status != "": + #if STOCHASTIC[i]['slow_k'] < 40: + status += temp_status + + # 120 + temp_status = self.common.check_Dolpa_Jiji(STOCK, i, '120') + if temp_status != "": + #if STOCHASTIC[i]['slow_k'] < 40: + status += temp_status + + # 240 + temp_status = self.common.check_Dolpa_Jiji(STOCK, i, '240') + if temp_status != "": + #if STOCHASTIC[i]['slow_k'] < 40: + status += temp_status + + # 270일 최고가 돌파 + temp_status = self.common.check_highest_270(STOCK, i) + if temp_status != "": + # if STOCHASTIC[i]['slow_k'] < 40: + status += temp_status + + # 20일선 지지 매수가 추천 + temp_status = self.common.check_Dolpa_Jiji_20(STOCK, i) + if temp_status != "": + # if STOCHASTIC[i]['slow_k'] < 40: + status += temp_status + + # 단타 #1 + temp_status = self.common.check_Danta1(STOCK, i) + if temp_status != "": + # if STOCHASTIC[i]['slow_k'] < 40: + status += temp_status + + # 단타 #2 + temp_status = self.common.check_Danta2(STOCK, i) + if temp_status != "": + # if STOCHASTIC[i]['slow_k'] < 40: + status += temp_status all_upper_cross_status = self.common.checkAllUpperCross(STOCK, i) if all_upper_cross_status != "": status += all_upper_cross_status + # 1주일 동안 몇 10% 이상 오른 종목 + w1Rate = self.common.check_W1Rate(STOCK, i) + if w1Rate != "": + status += w1Rate + # GOLDENCROSS#1은 바로 매수하지 않고, 이 시점 이후로 5일선이 20일선을 하방으로 뚫었다가 다시 20일선을 상방으로 뚫는 순간 매수를 시도한다. # GOLDENCROSS#2은 바로 매수 가능 # GOLDENCROSS#3은 바로 매수 가능 @@ -337,11 +245,6 @@ class Analyzer: if bearmarket_buying_status != "": status += bearmarket_buying_status - # BUYINGSTOCHASTIC#1은 바로 매수 가능 - stochastic_buying_status = self.common.check_stochastic_buying(STOCK, STOCHASTIC, ICHIMOKU, i) - if stochastic_buying_status != "": - status += stochastic_buying_status - # STOCHASTIC stochastic_status = self.common.check_stochastic(STOCK, STOCHASTIC, i) if stochastic_status != "": @@ -376,51 +279,74 @@ class Analyzer: if ((item_code in self.fnguide and not self.fnguide[item_code]) or (item_code == "KOSPI" or item_code == "KOSDAK") or result[3] == ''): rowid += 1 # 다음 종목을 가져옴 - cursor.execute('SELECT * FROM ' + self.tableName + ' WHERE rowid=?', (rowid,)) + cursor.execute('SELECT CODE, NAME, PRICE, STOCHASTIC FROM ' + self.tableName + ' WHERE rowid=?', (rowid,)) result = cursor.fetchone() continue result_3 = result[3] - result_4 = result[4] - result_5 = result[5] - result_6 = result[6] - if result[3] != result[3]: result_3 = result[3].replace("NaN", "0") - if result[4] != result[4]: result_4 = result[4].replace("NaN", "0") - if result[5] != result[5]: result_5 = result[5].replace("NaN", "0") - if result[6] != result[6]: result_6 = result[6].replace("NaN", "0") + if result[3] != result[3]: + result_3 = result[3].replace("NaN", "0") + if result[3]==None: + rowid += 1 + cursor.execute('SELECT CODE, NAME, PRICE, STOCHASTIC FROM ' + self.tableName + ' WHERE rowid=?', (rowid,)) + result = cursor.fetchone() + continue - stock = {"CODE": result[0], "NAME": result[1], "PRICE": json.loads(result[2]), "MACD": json.loads(result_3), "STOCHASTIC": json.loads(result_4), "ICHIMOKU": json.loads(result_5), "RSI": json.loads(result_6)} + stock = {"CODE": result[0], "NAME": result[1], "PRICE": json.loads(result[2]), "STOCHASTIC": json.loads(result_3)} last_index = self.get_last_index(stock) STOCK = stock['PRICE'] - MACD = stock['MACD'] STOCHASTIC = stock['STOCHASTIC'] - ICHIMOKU = stock['ICHIMOKU'] - RSI = stock['RSI'] stochastic_score = STOCHASTIC[last_index]['slow_k'] if stochastic_score < 50: - macd_score = MACD[last_index]['macd'] - rsi_score = RSI[last_index]['rsi'] - ichimoku_score = ICHIMOKU[last_index]['ichimoku_buy'] # 종목 상태 체크 분석 - state, buy_price = self.analyzeFinalScore(last_index, STOCK, MACD, STOCHASTIC, ICHIMOKU, RSI) + state, buy_price = self.analyzeFinalScore(last_index, STOCK, STOCHASTIC) if state != "": fig = self.draw(stock) - title = "%s (%s), %s, buy_price (%d), stochastic(%.3f), rsi(%.3f), macd(%.3f), ichimoku(%d) 차트" % (item_name, item_code, state, buy_price, stochastic_score, rsi_score, macd_score, ichimoku_score) + title = "%s (%s), %s, buy_price (%d), stochastic(%.3f) 차트" % (item_name, item_code, state, buy_price, stochastic_score) fig['layout'].update(title=title) - fileName = "%s/%s__%.3f__%.3f__%s_%s.html" % (outPath, state, stochastic_score, rsi_score, item_name.replace(" ", ""), item_code) + fileName = "%s/%s__%.3f__%s_%s.html" % (outPath, state, stochastic_score, item_name.replace(" ", ""), item_code) po.write_html(fig, file=fileName, auto_open=False) else: - if (RSI[last_index]['rsi_buy'] == 1) and STOCK[last_index]['volume'] > 1000000: + if STOCK[last_index]['volume'] > 1000000: fig = self.draw(stock) - title = "%s (%s) buy_price (%d), stochastic(%.3f), rsi(%.3f), macd(%.3f), ichimoku(%d) 차트"%(item_name, item_code, buy_price, stochastic_score, rsi_score, macd_score, ichimoku_score) + title = "%s (%s) buy_price (%d), stochastic(%.3f) 차트"%(item_name, item_code, buy_price, stochastic_score) fig['layout'].update(title=title) - fileName = "%s/%.3f__%.3f__%s_%s.html"%(tmp_path, stochastic_score, rsi_score, item_name.replace(" ", ""), item_code) + fileName = "%s/%.3f__%s_%s.html"%(tmp_path, stochastic_score, item_name.replace(" ", ""), item_code) po.write_html(fig, file=fileName, auto_open=False) + """ + try: + stock = {"CODE": result[0], "NAME": result[1], "PRICE": json.loads(result[2]), "STOCHASTIC": json.loads(result_3)} + last_index = self.get_last_index(stock) + STOCK = stock['PRICE'] + STOCHASTIC = stock['STOCHASTIC'] + + stochastic_score = STOCHASTIC[last_index]['slow_k'] + if stochastic_score < 50: + + # 종목 상태 체크 분석 + state, buy_price = self.analyzeFinalScore(last_index, STOCK, STOCHASTIC) + + if state != "": + fig = self.draw(stock) + title = "%s (%s), %s, buy_price (%d), stochastic(%.3f) 차트" % (item_name, item_code, state, buy_price, stochastic_score) + fig['layout'].update(title=title) + fileName = "%s/%s__%.3f__%s_%s.html" % (outPath, state, stochastic_score, item_name.replace(" ", ""), item_code) + po.write_html(fig, file=fileName, auto_open=False) + else: + if STOCK[last_index]['volume'] > 1000000: + fig = self.draw(stock) + title = "%s (%s) buy_price (%d), stochastic(%.3f) 차트"%(item_name, item_code, buy_price, stochastic_score) + fig['layout'].update(title=title) + fileName = "%s/%.3f__%s_%s.html"%(tmp_path, stochastic_score, item_name.replace(" ", ""), item_code) + po.write_html(fig, file=fileName, auto_open=False) + except: + print ("error") + """ rowid += 1 cursor.execute('SELECT * FROM ' + self.tableName + ' WHERE rowid=?', (rowid,)) result = cursor.fetchone() @@ -434,7 +360,7 @@ class Analyzer: cursor = conn.cursor() # 기존 분석 데이터를 모두 지움 - cursor.execute('update ' + self.tableName + ' set ICHIMOKU = "", MACD = "", STOCHASTIC = "", RSI = ""') + cursor.execute('update ' + self.tableName + ' set STOCHASTIC = ""') rowid = 1 cursor.execute('SELECT * FROM ' + self.tableName + ' WHERE rowid=?', (rowid,)) @@ -443,17 +369,8 @@ class Analyzer: stock = {"CODE": result[0], "NAME": result[1], "PRICE": json.loads(result[2])} try: - results_ICHIMOKU = self.ichimokuCloud.analyze(stock) - text_ICHIMOKU = json.dumps(results_ICHIMOKU, ensure_ascii=False) - - results_MACD = self.macd.analyze(stock) - text_MACD = json.dumps(results_MACD, ensure_ascii=False) - results_STOCHASTIC = self.stochastic.analyze(stock) text_STOCHASTIC = json.dumps(results_STOCHASTIC, ensure_ascii=False) - - results_RSI = self.rsi.analyze(stock) - text_RSI = json.dumps(results_RSI, ensure_ascii=False) except: print("#", rowid, stock['NAME']) rowid += 1 @@ -461,7 +378,7 @@ class Analyzer: result = cursor.fetchone() continue - cursor.execute("UPDATE " + self.tableName + " SET ICHIMOKU=?, MACD=?, STOCHASTIC=?, RSI=? WHERE CODE=?", (text_ICHIMOKU,text_MACD,text_STOCHASTIC,text_RSI, stock["CODE"])) + cursor.execute("UPDATE " + self.tableName + " SET STOCHASTIC=? WHERE CODE=?", (text_STOCHASTIC, stock["CODE"])) print("#", rowid, stock['NAME']) rowid += 1 cursor.execute('SELECT * FROM ' + self.tableName + ' WHERE rowid=?', (rowid,)) @@ -483,14 +400,8 @@ if __name__ == "__main__": # 분석 & update DB """ - #print ("analyze IchimokuCloud...") - analyzer.analyzeIchimokuCloud() - #print ("analyze MACD...") - analyzer.analyzeMACD() #print ("analyze Stochastic...") analyzer.analyzeStochastic() - #print ("analyze RSI...") - analyzer.analyzeRSI() """ ###analyzer.analyze() diff --git a/stockpredictor/analysis/Common.py b/stockpredictor/analysis/Common.py index b6ad142..ba919ca 100644 --- a/stockpredictor/analysis/Common.py +++ b/stockpredictor/analysis/Common.py @@ -229,124 +229,127 @@ class Common: return "STOCHASTIC#2_" return "" - def check_days5_20_line_buying(self, stock, i): - """ - 5일 선이 20일 선을 뚫고 올라온 순간 체크 - 5일선이 다시 20선 아래로 내려가는 순간 손걸한다. - """ - if stock[i]['close'] == stock[i]['high']: - # 윗꼬리 없는 양봉이어야 한다. - return "" + def check_highest_270(self, stock, i): + # 270일 기준으로 최고가를 기록하는 순간 매수를 시도한다. + # https://docs.google.com/presentation/d/1MVuaeRNljqLCdn4dPZmvVdtl2Ab09Zwg/edit#slide=id.gc7b796e645_0_27 + upper_index = 0 + if len(stock) > 271: + top = 0 + for idx in range(2, 271): + # 최근 270일 중 최고가를 구한다. + if top < stock[-idx]['close']: + top = stock[-idx]['close'] - if len(stock) > 61: - # 오늘 종가가 20일선을 뚫고 올라왔다. (20일선<오늘종가 and (어제종가<20 or 어제5일선<20)) - # 오늘 종가는 양봉이어야 한다. - # 어제부터 index1일까지 20일선이 5일선 위에 있었다. - # index1일부터 index2일까지 5일선이 20일선 위에 있었다. - # 이전 5일선이 20일선을 뚫었던 종가보다 오늘 뚫은 종가가 높거나 혹은 오늘 종가가 더 낮더라도 장대 양봉어어야 한다. - # 주봉의 20일 평균이 이전 주봉의 20일 평균 보다 높아야 한다. - if stock[i]['avg20'] < stock[i]['close'] and (stock[i-1]['close'] < stock[i]['avg20'] or stock[i-1]['avg5'] < stock[i]['avg20']): - if (stock[i-3]['avg5'] < stock[i-3]['avg20'] or stock[i-2]['avg5'] < stock[i-2]['avg20'] or stock[i-1]['avg5'] < stock[i-1]['avg20']): - #if (stock[i - 1]['avg5'] < stock[i - 1]['avg20']): - if stock[i]['open'] < stock[i]['close']: - index1 = -1 - for j in range(1, 61): - if stock[i-j]['avg20'] < stock[i-j]['avg5']: - index1 = j - break - index2 = -1 - for j in range(index1+1, 61): - if stock[i-j]['avg5'] < stock[i-j]['avg20']: - index2 = j - break - if (index2 != -1 and ((stock[i-index2]['close'] < stock[i]['close']) or (stock[i]['high']-stock[i]['close'] < stock[i]['open']-stock[i]['low']))): - # 주봉의 20일 평균이 이전 주봉의 20일 평균 보다 높아야 한다. - return "5-20_" + if top < stock[i]['close']: + return "highest_" return "" - def check_days5_60_line_buying(self, stock, i): - """ - 5일 선이 60일 선을 뚫고 올라온 순간 체크 - 5일선이 다시 60선 아래로 내려가는 순간 손걸한다. - """ - if stock[i]['close'] == stock[i]['high']: - # 윗꼬리 없는 양봉이어야 한다. - return "" + def check_Dolpa_Jiji(self, stock, i, day='20'): + upper_index = 0 + if len(stock) > 5: + for idx in range(1, 5): + # day선을 돌파하는 양봉이고, 종가가 최고가 보다 100 이내이어야 한다. + if stock[-idx]['open'] < stock[-idx]["avg"+day] < stock[-idx]['close'] and stock[-idx]['high'] - 100 <= stock[-idx]['close']: + upper_index = idx + break + if upper_index != 0: + for cidx in range(1, upper_index): + # 해당일의 종가보다 현재의 시가가 높거나 같아야 하며, 현재가는 양봉이어야 한다. + if stock[-upper_index]['close'] <= stock[-cidx]['open'] and stock[-cidx]['open'] < stock[-cidx]['close']: + # 해당 기준일 선은 상승이어야 한다. + if stock[-upper_index]['avg'+day] < stock[-cidx]['avg'+day]: + return day + "_" + return "" + def check_Dolpa_Jiji_20(self, stock, i): + """ + top: 이전 5일선이 20일선 위에 있을 때 최고가 + top일 체크 사항 (20일 < 5일선) + 5일선이 20일 선으로 내려왔다가 다시 20일선 위로 올라왔고, top < 오늘 시가 + 100 + top < 시가 < 종가 라면 다음날 매수한다. + # https://docs.google.com/presentation/d/1MVuaeRNljqLCdn4dPZmvVdtl2Ab09Zwg/edit#slide=id.gc7b796e645_0_80 + """ if len(stock) > 61: - # 오늘 5일선이 60일선 위에 올라왔다. - # 어제부터 index1일까지 60일선이 5일선 위에 있었다. - # index1일부터 index2일까지 5일선이 60일선 위에 있었다. - if stock[i]['avg60'] < stock[i]['avg5']: - if (stock[i - 3]['avg5'] < stock[i - 3]['avg60'] or stock[i - 2]['avg5'] < stock[i - 2]['avg60'] or stock[i - 1]['avg5'] < stock[i - 1]['avg60']): - #if (stock[i - 1]['avg5'] < stock[i - 1]['avg60']): + if stock[i]['avg20'] < stock[i]['close'] and stock[i]['avg20'] < stock[i]['open']: + if stock[i]['avg5'] < stock[i]['avg20']: index1 = -1 - for j in range(1, 150): - if stock[i-j]['avg60'] < stock[i-j]['avg5']: + for j in range(1, 61): + if stock[i-j]['avg20'] < stock[i-j]['avg5']: index1 = j break - index2 = -1 - for j in range(index1+1, 150): - if stock[i-j]['avg5'] < stock[i-j]['avg60']: - index2 = j + top = 0 + for j in range(index1+1, 61): + if stock[i - j]['open'] < stock[i - j]['close']: + if top < stock[i - j]['close']: + top = stock[i - j]['close'] + else: + if top < stock[i - j]['open']: + top = stock[i - j]['open'] + if stock[i-j]['avg5'] < stock[i-j]['avg20']: break - if (index2 != -1 and (stock[i-index2+1]['close'] < stock[i]['close'])): - return "5-60_" + return "5-20_" return "" - def check_days20_60_line_buying(self, stock, i): + def check_Danta1(self, stock, i): """ - 20일 선이 60일 선을 뚫고 올라온 순간 체크 - 20일선이 다시 60선 아래로 내려가는 순간 손걸한다. - """ - if stock[i]['close'] == stock[i]['high']: - # 윗꼬리 없는 양봉이어야 한다. - return "" + 어제 상한가 혹은 상승양봉이 나온다. + 오늘 상승 출발을 해야 하며 상승 음봉이 나온다 + - 어제 종가 = 어제 상한가 < 종가 < 시가 < 상한가 + https://docs.google.com/presentation/d/1MVuaeRNljqLCdn4dPZmvVdtl2Ab09Zwg/edit#slide=id.gc7b796e645_0_109 - if len(stock) > 151: - # 오늘 20일선이 60일선 위에 올라왔다. - # 어제부터 index1일까지 60일선이 20일선 위에 있었다. - # index1일부터 index2일까지 20일선이 60일선 위에 있었다. - if stock[i]['avg60'] < stock[i]['avg20']: - if (stock[i - 3]['avg20'] < stock[i - 3]['avg60'] or stock[i - 2]['avg20'] < stock[i - 2]['avg60'] or stock[i - 1]['avg20'] < stock[i - 1]['avg60']): - #if (stock[i - 1]['avg20'] < stock[i - 1]['avg60']): - index1 = -1 - for j in range(1, 150): - if stock[i-j]['avg60'] < stock[i-j]['avg20']: - index1 = j - break - index2 = -1 - for j in range(index1+1, 150): - if stock[i-j]['avg20'] < stock[i-j]['avg60']: - index2 = j - break - if (index2 != -1 and (stock[i-index2+1]['close'] < stock[i]['close'])): - return "20-60_" + 만약 다음날 시작초가가 오늘 종가보다 높게 상승으로 출발한다면 매수를 한다. + 손절가는 오늘 최저가이다. + """ + if stock[i-1]['open'] < stock[i-1]['close'] == stock[i-1]['high']: + if stock[i-1]['close'] < stock[i]['close'] < stock[i]['open'] < stock[i]['high']: + return "danta1_" return "" - def check_days5_120_line_buying(self, stock, i): - if stock[i]['close'] == stock[i]['high']: - # 윗꼬리 없는 양봉이어야 한다. - return "" + def check_Danta2(self, stock, i): + """ + 쐐기, 수렴, 깃대 패턴 확인 + # https://docs.google.com/presentation/d/1MVuaeRNljqLCdn4dPZmvVdtl2Ab09Zwg/edit#slide=id.gc7b796e645_0_144 + 상단 추세선을 돌파하면 매수를 한다. """ - 5일 선이 120일 선을 뚫고 올라온 순간 체크 - """ - if stock[i-1]['close'] < stock[i-1]['avg120']: - if stock[i]['avg120'] < stock[i]['close']: - return "5-120_" + price_10 = round(stock[i]["close"] / 10) + if stock[-i]["open"] < stock[-i]["close"]: + top = stock[-i]["close"] + bottom = stock[-i]["open"] + else: + top = stock[-i]["open"] + bottom = stock[-i]["close"] + + if len(stock) > 21: + for i in range(2, 21): + if stock[-i]["open"] < stock[-i]["close"]: + if top < stock[-i]["close"]: + top = stock[-i]["close"] + if stock[-i]["open"] < bottom: + bottom = stock[-i]["open"] + else: + if top < stock[-i]["open"]: + top = stock[-i]["open"] + if stock[-i]["close"] < bottom: + bottom = stock[-i]["close"] + + if top - bottom < price_10: + return "danta2_" return "" - def check_days5_240_line_buying(self, stock, i): - if stock[i]['close'] == stock[i]['high']: - # 윗꼬리 없는 양봉이어야 한다. - return "" - + def check_RightArrange(self, stock, i): """ - 5일 선이 240일 선을 뚫고 올라온 순간 체크 + 어제는 정배열이 아니었는데, 오늘은 정배열인 경우 """ - if stock[i-1]['close'] < stock[i-1]['avg240']: - if stock[i]['avg240'] < stock[i]['close']: - return "5-240_" + if len(stock) > 2: + if (not (stock[i-1]["avg120"] < stock[i-1]["avg60"] < stock[i-1]["avg20"] < stock[i-1]["avg5"]) and + (stock[i]["avg120"] < stock[i]["avg60"] < stock[i]["avg20"] < stock[i]["avg5"])): + return "arrange_" return "" + def check_W1Rate(self, stock, i): + if len(stock) > 5: + rate = round((stock[i]["close"] - stock[i-4]["close"]) / stock[i-4]["close"],2) + if rate >= 0.05: + return "1w("+str(rate)+")_" + return "" \ No newline at end of file diff --git a/stockpredictor/crawler/toSQLite/Crawler.py b/stockpredictor/crawler/toSQLite/Crawler.py index 23edcf7..ae34084 100644 --- a/stockpredictor/crawler/toSQLite/Crawler.py +++ b/stockpredictor/crawler/toSQLite/Crawler.py @@ -21,6 +21,7 @@ print("[KOSPI 상장기업 재무제표 다운로드]") crawler.crawl_fnguide(inFnguideFileName) """ + crawler = MetaCrawler() print("\n[환율 (USD, JPY, EUR, CNY), 원유 (WTI), 국제금]") inFileName = PROJECT_HOME + '/resources/meta_1.db' @@ -52,12 +53,13 @@ crawler = StockCrawler() crawler.saveIndex("KOSPI", kospiFileName, outFileName) crawler.saveIndex("KOSDAK", kosdakFileName, outFileName) + print("\n[종목 분석]") # S: 분석까지 진행 inFileName = PROJECT_HOME + '/resources/stock.db' analyzer = Analyzer(PROJECT_HOME, inFileName, inFnguideFileName) analyzer.analyze() - +3 print("\n[종목 결정]") day = datetime.datetime.today().strftime("%Y%m%d") outPath = PROJECT_HOME + "/resources/analysis/" + day @@ -68,6 +70,7 @@ print("print to Html...") analyzer.analyzeToHtml(outPath) # E: 분석까지 진행 + print("time : %6.2f 초", (time.time() - start)) print ("done...") \ No newline at end of file