diff --git a/stockpredictor/analysis/Analyzer.py b/stockpredictor/analysis/Analyzer.py index f42043d..d66a916 100644 --- a/stockpredictor/analysis/Analyzer.py +++ b/stockpredictor/analysis/Analyzer.py @@ -199,12 +199,6 @@ class Analyzer: #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 != "": @@ -256,9 +250,100 @@ class Analyzer: status += stochastic_status # YANGBONG - if self.common.checkLongYangBongAfterUmBong(STOCK, i): + longYangBongAfterUmBong_status = self.common.checkLongYangBongAfterUmBong(STOCK, i) # 어제 음봉 이후 장대양봉이었다면, - status += 'YANGBONG_' + if longYangBongAfterUmBong_status != "": + status += longYangBongAfterUmBong_status + + # Doji + doji_status = self.common.checkDoji(STOCK, i) + # 하락 추세에서 도지가 나오면 매수 + if doji_status != "": + status += doji_status + + """ + # Gravestone + gravestone_status = self.common.checkGravestone(STOCK, i) + # 상승 추세에서 그레이브스톤이 나오면 매도 + if gravestone_status != "": + status += gravestone_status + """ + + # Dragonfly + dragonfly_status = self.common.checkDragonfly(STOCK, i) + # 하락 추세에서 드레곤플라이가 나오면 매수 + if dragonfly_status != "": + status += dragonfly_status + + # Hammer + hammer_status = self.common.checkHammer(STOCK, i) + # 하락 추세에서 해머가 나오면 매수 + if hammer_status != "": + status += hammer_status + + """ + # Hangingman + hangingman_status = self.common.checkHangingman(STOCK, i) + # 상승 추세에서 행잉맨이 나오면 매도 + if hangingman_status != "": + status += hangingman_status + """ + + # 상승장악형 (Engulfing) - 다음 날도 양봉이라면 매수 + engulfing_status = self.common.checkEngulfingHigh(STOCK, i) + # 하락 추세에서 상승장악형이 나오면 매수 + if engulfing_status != "": + status += engulfing_status + + """ + # 하락장악형 (Engulfing) + engulfing_status = self.common.checkEngulfingLow(STOCK, i) + # 상승 추세에서 하락장악형이 나오면 매도 + if engulfing_status != "": + status += engulfing_status + """ + + # 상승 포아형 (Harami) + harami_status = self.common.checkHaramiHigh(STOCK, i) + # 하락 추세에서 상승포아형이 나오면 매수 + if harami_status != "": + status += harami_status + + """ + # 하락 포아형 (Harami) + harami_status = self.common.checkHaramiLow(STOCK, i) + # 상승 추세에서 하락포아형이 나오면 매도 + if harami_status != "": + status += harami_status + """ + + # 관통형 (piercing) + piercing_status = self.common.checkPiercing(STOCK, i) + # 하락 추세에서 관통형이 나오면 매수 + if piercing_status != "": + status += piercing_status + + """ + # 흑운형 (Dark-cloud) + darkcloud_status = self.common.checkDarkCloud(STOCK, i) + # 상승 추세에서 흑운형이 나오면 매도 + if darkcloud_status != "": + status += darkcloud_status + """ + + # 샛별 (Morning start) + morningstar_status = self.common.checkMorningstar(STOCK, i) + # 하락 추세에서 샛별형이 나오면 매수 + if morningstar_status != "": + status += morningstar_status + + """ + # 저녁별 (Evening start) + eveningstar_status = self.common.checkEveningstar(STOCK, i) + # 상승 추세에서 저녁별형이 나오면 매도 + if eveningstar_status != "": + status += eveningstar_status + """ return status, buy_price @@ -279,6 +364,13 @@ class Analyzer: item_name = result[1] print("#html", rowid, item_name) + if item_code != "050960": + rowid += 1 + cursor.execute('SELECT CODE, NAME, PRICE, STOCHASTIC FROM ' + self.tableName + ' WHERE rowid=?', (rowid,)) + result = cursor.fetchone() + continue + + # 부실 기업은 매수하지 않고 그냥 넘긴다. # kospi 지수와 kosdak 지수도 그냥 넘긴다. if ((item_code in self.fnguide and not self.fnguide[item_code]) or (item_code == "KOSPI" or item_code == "KOSDAK") or result[3] == ''): diff --git a/stockpredictor/analysis/Analyzer_1.py b/stockpredictor/analysis/Analyzer_1.py new file mode 100644 index 0000000..f42043d --- /dev/null +++ b/stockpredictor/analysis/Analyzer_1.py @@ -0,0 +1,432 @@ +import json +import os +import time +import shutil +from stockpredictor.analysis.Common import Common +from stockpredictor.analysis.Stochastic import Stochastic +import matplotlib.pyplot as plt +import datetime +import sqlite3 +from datetime import datetime + +from matplotlib import rc + +rc('font', family='AppleGothic') +plt.rcParams['axes.unicode_minus'] = False + +import pandas as pd +import plotly.graph_objs as go +from plotly import tools, subplots +import plotly.io as po + +class Analyzer: + tableName = 'stock' + PROJECT_HOME = None + + stocks = None + candidate = None + + stochastic = None + + common = None + inFileName = None + fnguideFileName = None + + fnguide = {} + + def __init__(self, PROJECT_HOME, inFileName, fnguideFileName): + self.PROJECT_HOME = PROJECT_HOME + self.inFileName = inFileName + self.fnguideFileName = fnguideFileName + + self.stocks = [] + self.candidate = [] + + self.common = Common() + + self.stochastic = Stochastic() + + self.readFnguide() + return + + def readFnguide(self): + conn = sqlite3.connect(self.fnguideFileName) + cursor = conn.cursor() + + today = datetime.today() + year1 = str(today.year - 1) + ".12.01" + year2 = str(today.year - 2) + ".12.01" + year3 = str(today.year - 3) + ".12.01" + + rowid = 1 + cursor.execute('SELECT * FROM fnguide WHERE rowid=?', (rowid,)) + result = cursor.fetchone() + while result != None: + data = json.loads(result[2]) + self.fnguide[result[0]] = True + + if (year1 in data and year2 in data and year3 in data): + if (data[year1]['영업이익'] < 0 and data[year2]['영업이익'] < 0 and data[year3]['영업이익'] < 0): + # 3년 연속 영업이익이 적자이면 매수하지 않는다. + self.fnguide[result[0]] = False + if (data[year1]['영업이익'] < -100): + # 전년 영억적자가 100억 이상이면 매수하지 않는다. + self.fnguide[result[0]] = False + + rowid += 1 + cursor.execute('SELECT * FROM fnguide WHERE rowid=?', (rowid,)) + result = cursor.fetchone() + + cursor.close() + conn.close() + return + + def draw(self, stock): + + last_index = self.get_last_index(stock) + if last_index > 300: + index = 300 # 최대 300일치 그래프 확인 + df_stock = pd.DataFrame(stock["PRICE"][len(stock["PRICE"]) - index:]) + df_stochastic = pd.DataFrame(stock["STOCHASTIC"][len(stock["STOCHASTIC"]) - index:last_index+1]) + else: + index = last_index + df_stock = pd.DataFrame(stock["PRICE"][:index+1]) + df_stochastic = pd.DataFrame(stock["STOCHASTIC"][:index+1]) + + # general + volume = go.Bar(x=df_stock.DATE, y=df_stock['volume'], name="volume") + volume_data = [volume] + + # 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] + + fig = subplots.make_subplots(rows=2, cols=1, subplot_titles=('거래량', 'Stochastic')) + + for trace in volume_data: + fig.append_trace(trace, 1, 1) + for trace in stochastic_data: + fig.append_trace(trace, 2, 1) + + fig.update_layout(height=800) + + return fig + + def get_last_index(self, stock): + for i in range(0, len(stock['PRICE'])): + if (stock['PRICE'][i]['close'] == 0 and stock['PRICE'][i]['open'] == 0 and stock['PRICE'][i]['volume'] == 0): + return i-1 + return len(stock['PRICE']) - 1 + + def analyzeStochastic(self): + conn = sqlite3.connect(self.inFileName) + cursor = conn.cursor() + + # 기존 분석 데이터를 모두 지움 + cursor.execute('update ' + self.tableName + ' set STOCHASTIC = ""') + + 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.stochastic.analyze(stock) + text = json.dumps(results, ensure_ascii=False) + cursor.execute("UPDATE " + self.tableName + " SET STOCHASTIC=? WHERE CODE=?", (text, stock["CODE"])) + + print("#analyzeStochastic", 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, STOCHASTIC): + """ + 매수 조건 + #0. 최소 매수 조건은 거래량은 20만건, 종가는 2천원 이상인 종목이어야 한다. + #1. 골든크로스: 5일선, 20일선, 60일선, 120일선이 순서대로 나열되는 순간 + """ + i = last_index + buy_price = 0 + count = 0 + for idx in range(i, i-5, -1): + if idx-1 < 0: + break + buy_price += STOCK[idx-1]['close'] - STOCK[idx]['low'] + count += 1 + if count == 0: + buy_price = STOCK[i]['close'] + else: + # 종가 - 최저가의 최근 3일 평균 가격을 산정한다. + buy_price = round(STOCK[i]['close'] - (buy_price/count)) + + status = "" + if STOCK[i]['volume'] > 100000 and STOCK[i]['close'] > 2000: + # 거래량이 100만 이상이고, 종가가 1천원 이상인지 체크 (https://happpy-rich.tistory.com/94) + + # 정배열 체크 + temp_status = self.common.check_RightArrange(STOCK, i) + if temp_status != "": + #if STOCHASTIC[i]['slow_k'] < 40: + status += temp_status + + # 20일선 돌파 + temp_status = self.common.check_Dolpa_Jiji(STOCK, i, '20') + if temp_status != "": + #if STOCHASTIC[i]['slow_k'] < 40: + 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% 이상 오른 종목 + W1Rise = self.common.check_W1Rise(STOCK, i, 0.1) + if W1Rise != "": + status += W1Rise + + # 1일 동안 몇 10% 이상 내리 종목 + W1Fall = self.common.check_D1Fall(STOCK, i, -0.1) + if W1Fall != "": + status += W1Fall + + # GOLDENCROSS#1은 바로 매수하지 않고, 이 시점 이후로 5일선이 20일선을 하방으로 뚫었다가 다시 20일선을 상방으로 뚫는 순간 매수를 시도한다. + # GOLDENCROSS#2은 바로 매수 가능 + # GOLDENCROSS#3은 바로 매수 가능 + golden_cross_status = self.common.check_golded_cross(STOCK, i) + if golden_cross_status != "": + status += golden_cross_status + + # BUYINGBEARMARKET#1은 바로 매수 가능 + # BUYINGBEARMARKET#2은 바로 매수 가능 + bearmarket_buying_status = self.common.check_bearmarket_buying(STOCK, STOCHASTIC, i) + if bearmarket_buying_status != "": + status += bearmarket_buying_status + + # STOCHASTIC + stochastic_status = self.common.check_stochastic(STOCK, STOCHASTIC, i) + if stochastic_status != "": + status += stochastic_status + + # YANGBONG + if self.common.checkLongYangBongAfterUmBong(STOCK, i): + # 어제 음봉 이후 장대양봉이었다면, + status += 'YANGBONG_' + + return status, buy_price + + # 그래프 출력 + def analyzeToHtml(self, outPath): + tmp_path = outPath + "/tmp" + if os.path.isdir(tmp_path): + os.rmdir(tmp_path) + os.mkdir(tmp_path) + + conn = sqlite3.connect(self.inFileName) + cursor = conn.cursor() + rowid = 1 + cursor.execute('SELECT * FROM ' + self.tableName + ' WHERE rowid=?', (rowid,)) + result = cursor.fetchone() + while result != None: + item_code = result[0] + item_name = result[1] + print("#html", rowid, item_name) + + # 부실 기업은 매수하지 않고 그냥 넘긴다. + # kospi 지수와 kosdak 지수도 그냥 넘긴다. + 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 CODE, NAME, PRICE, STOCHASTIC FROM ' + self.tableName + ' WHERE rowid=?', (rowid,)) + result = cursor.fetchone() + continue + + result_3 = result[3] + 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]), "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) + """ + 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() + + cursor.close() + conn.close() + return + + def analyze(self): + conn = sqlite3.connect(self.inFileName) + cursor = conn.cursor() + + # 기존 분석 데이터를 모두 지움 + cursor.execute('update ' + self.tableName + ' set STOCHASTIC = ""') + + 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])} + + try: + results_STOCHASTIC = self.stochastic.analyze(stock) + text_STOCHASTIC = json.dumps(results_STOCHASTIC, ensure_ascii=False) + except: + print("#", rowid, stock['NAME']) + rowid += 1 + cursor.execute('SELECT * FROM ' + self.tableName + ' WHERE rowid=?', (rowid,)) + result = cursor.fetchone() + continue + + 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,)) + result = cursor.fetchone() + + conn.commit() + cursor.close() + conn.close() + return + + +if __name__ == "__main__": + + start = time.time() + PROJECT_HOME = "../.." + inFileName = PROJECT_HOME + '/resources/stock.db' + inFnguideFileName = PROJECT_HOME + '/resources/fnguide.db' + analyzer = Analyzer(PROJECT_HOME, inFileName, inFnguideFileName) + + # 분석 & update DB + """ + #print ("analyze Stochastic...") + analyzer.analyzeStochastic() + """ + + ###analyzer.analyze() + + day = datetime.today().strftime("%Y%m%d") + + # HTML 출력 + outPath = PROJECT_HOME + "/resources/analysis/"+day + if os.path.isdir(outPath): + shutil.rmtree(outPath) + os.mkdir(outPath) + print("print to Html...") + analyzer.analyzeToHtml(outPath) + + + # 파일 출력 + #print("print to File...") + #outFileName = PROJECT_HOME + '/resources/analysis/'+day+'.json' + #analyzer.analyzeToFile(outFileName) + + print("time : %6.2f 초", (time.time() - start)) + + print("done...") diff --git a/stockpredictor/analysis/Common.py b/stockpredictor/analysis/Common.py index 05d9dd9..b90174a 100644 --- a/stockpredictor/analysis/Common.py +++ b/stockpredictor/analysis/Common.py @@ -127,11 +127,196 @@ class Common: def checkLongYangBongAfterUmBong(self, stock, i): if i > 0: - if stock[i-1]['open'] > stock[i-1]['close']: # 어제가 음봉인지 체크 + if stock[i-1]['close'] < stock[i-1]['open']: # 어제가 음봉인지 체크 if stock[i]['open'] < stock[i]['close'] and stock[i]['close'] == stock[i]['high']: # 오늘 장대양봉인지 체크 if stock[i-1]['volume']*2 < stock[i]['volume']: # 어제 거래량 보다 두배 이상일 때 - return True - return False + return "UMYANG_" + return "" + + def checkDoji(self, stock, i): + # 하락 추세이고, 그저께, 어제 음봉이고, 오늘 도지인지 체크한다 + if i > 2: + # 하락 추세이고 + if stock[i - 1]['close'] < stock[i - 2]['close']: + # 그저께와 어제가 음봉인지 체크 + if stock[i-2]['close'] < stock[i-2]['open'] and stock[i-1]['close'] < stock[i-1]['open']: + # 도지 체크 + if stock[i]['open'] == stock[i]['close'] and stock[i]['low'] < stock[i]['close'] < stock[i]['high']: + return "DOJI_" + return "" + + def checkGravestone(self, stock, i): + # 상승 추세이고, 어제 양봉이고, 오늘 그레이브스톤인지 체크한다 + if i > 2: + # 상승 추세이고 + if stock[i-2]['close'] < stock[i - 1]['close']: + # 어제 양봉인지 체크 + if stock[i-1]['open'] < stock[i-1]['close']: + # 오늘 그레이브스톤인지 체크한다 + if stock[i]['open'] == stock[i]['close'] == stock[i]['low'] and stock[i]['low'] < stock[i]['high']: + return "GRAVESTONE_" + return "" + + def checkDragonfly(self, stock, i): + # 하락 추세이고, 그저께, 어제 음봉이고, 오늘 드레곤플라이인지 체크한다 + if i > 1: + # 하락 추세이고 + if stock[i - 1]['close'] < stock[i - 2]['close']: + # 그저께와 어제가 음봉인지 체크 + if stock[i - 2]['close'] < stock[i - 2]['open'] and stock[i - 1]['close'] < stock[i - 1]['open']: + # 오늘 드레곤플라이인지 체크한다 + if stock[i]['open'] == stock[i]['close'] == stock[i]['high'] and stock[i]['low'] < stock[i]['high']: + return "DRAGONEFLY_" + return "" + + def checkHammer(self, stock, i): + # 하락 추세이고, 그저께, 어제 음봉이고, 오늘 해머인지 체크한다 + if i > 1: + # 하락 추세이고 + if stock[i - 1]['close'] < stock[i - 2]['close']: + # 그저께와 어제가 음봉인지 체크 + if stock[i - 2]['close'] < stock[i - 2]['open'] and stock[i - 1]['close'] < stock[i - 1]['open']: + # 오늘 해머인지 체크한다 + if stock[i]['open'] < stock[i]['close']: + if (stock[i]['close'] - stock[i]['open']) * 2 < stock[i]['open'] - stock[i]['low']: + # 윗꼬리가 몸통보다 짧아야 한다. + if stock[i]['high'] - stock[i]['close'] < stock[i]['close'] - stock[i]['open']: + return "HAMMER_" + if stock[i]['close'] < stock[i]['open']: + if (stock[i]['open'] - stock[i]['close']) * 2 < stock[i]['close'] - stock[i]['low']: + # 윗꼬리가 몸통보다 짧아야 한다. + if stock[i]['high'] - stock[i]['open'] < stock[i]['open'] - stock[i]['close']: + return "HAMMER_" + return "" + + def checkHangingman(self, stock, i): + # 상승 추세이고, 어제 양봉이고, 오늘 행잉맨인지 체크한다 + if i > 2: + # 상승 추세이고 + if stock[i-2]['close'] < stock[i - 1]['close']: + # 어제 양봉인지 체크 + if stock[i-1]['open'] < stock[i-1]['close']: + # 오늘 해머인지 체크한다 + if stock[i]['open'] < stock[i]['close']: + if (stock[i]['close'] - stock[i]['open']) * 2 < stock[i]['open'] - stock[i]['low']: + # 윗꼬리가 몸통보다 짧아야 한다. + if stock[i]['high'] - stock[i]['close'] < stock[i]['close'] - stock[i]['open']: + return "HANGINGMAN_" + if stock[i]['close'] < stock[i]['open']: + if (stock[i]['open'] - stock[i]['close']) * 2 < stock[i]['close'] - stock[i]['low']: + # 윗꼬리가 몸통보다 짧아야 한다. + if stock[i]['high'] - stock[i]['open'] < stock[i]['open'] - stock[i]['close']: + return "HANGINGMAN_" + return "" + + def checkEngulfingHigh(self, stock, i): + # 하락 추세에서 상승 장악형인지 체크 + if i > 2: + # 하락 추세이고 + if stock[i - 1]['close'] < stock[i - 2]['close']: + # 그저께와 어제가 음봉인지 체크 + if stock[i - 2]['close'] < stock[i - 2]['open'] and stock[i - 1]['close'] < stock[i - 1]['open']: + # 오늘 상승장악형인지 체크 + if stock[i]['open'] < stock[i]['close']: + if stock[i-1]['open'] < stock[i]['close'] and stock[i]['open'] < stock[i-1]['close']: + return "ENHIGH_" + return "" + + def checkEngulfingLow(self, stock, i): + # 상승 추세에서 하락 장악형인지 체크 + if i > 2: + # 상승 추세이고 + if stock[i - 2]['close'] < stock[i - 1]['close']: + # 어제 양봉인지 체크 + if stock[i - 1]['open'] < stock[i - 1]['close']: + # 오늘 하락장악형인지 체크 + if stock[i]['close'] < stock[i]['open']: + if stock[i-1]['close'] < stock[i]['open'] and stock[i]['close'] < stock[i-1]['open']: + return "ENLOW_" + return "" + + def checkHaramiHigh(self, stock, i): + # # 하락 추세에서 상승포아형인지 체크 + if i > 2: + # 하락 추세이고 + if stock[i - 1]['close'] < stock[i - 2]['close']: + # 그저께와 어제가 음봉인지 체크 + if stock[i - 2]['close'] < stock[i - 2]['open'] and stock[i - 1]['close'] < stock[i - 1]['open']: + # 오늘 상승포아형인지 체크 + if stock[i]['open'] < stock[i]['close']: + if stock[i-1]['close'] < stock[i]['low'] and stock[i]['high'] < stock[i-1]['open']: + return "HAHIGH_" + return "" + + def checkHaramiLow(self, stock, i): + # 상승 추세에서 하락 포아형인지 체크 + if i > 2: + # 상승 추세이고 + if stock[i - 2]['close'] < stock[i - 1]['close']: + # 어제 양봉인지 체크 + if stock[i - 1]['open'] < stock[i - 1]['close']: + # 오늘 하락포아형인지 체크 + if stock[i]['close'] < stock[i]['open']: + if stock[i-1]['open'] < stock[i]['low'] and stock[i]['high'] < stock[i-1]['close']: + return "HALOW_" + return "" + + def checkPiercing(self, stock, i): + # 하락 추세에서 관통형인지 체크 + if i > 2: + # 하락 추세이고 + if stock[i - 1]['close'] < stock[i - 2]['close']: + # 그저께와 어제가 음봉인지 체크 + if stock[i - 2]['close'] < stock[i - 2]['open'] and stock[i - 1]['close'] < stock[i - 1]['open']: + # 오늘 관통형인지 체크 + if stock[i]['open'] < stock[i]['close']: + if stock[i]['open'] < stock[i-1]['low'] and (stock[i-1]['close'] + stock[i-1]['open'])/2 < stock[i]['close'] < stock[i-1]['close']: + return "PIERCING_" + return "" + + def checkDarkCloud(self, stock, i): + # 상승 추세에서 흑운형인지 체크 + if i > 2: + # 상승 추세이고 + if stock[i - 2]['close'] < stock[i - 1]['close']: + # 어제 양봉인지 체크 + if stock[i - 1]['open'] < stock[i - 1]['close']: + # 오늘 흑운형인지 체크 + if stock[i]['close'] < stock[i]['open']: + if stock[i-1]['high'] < stock[i]['open'] and stock[i-1]['open'] < stock[i]['close'] < (stock[i-1]['open'] + stock[i-1]['close'])/2: + return "DARKCLOUD_" + return "" + + def checkMorningstar(self, stock, i): + # 하락 추세에서 샛별인지 체크 + if i > 3: + # 하락 추세이고 + if stock[i-1]['close'] < stock[i-2]['close']: + # 그저께와 어제가 음봉인지 체크 + if stock[i - 2]['close'] < stock[i - 2]['open'] and stock[i - 1]['close'] < stock[i - 1]['open']: + # 오늘 샛별인지 체크 + # 어제 갭 체크 + if stock[i-1]['open'] < stock[i - 2]['close'] and stock[i-1]['close'] < stock[i - 2]['close']: + # 오늘 시가가 어제 종가보다 높으며 양봉 + if stock[i-1]['close'] < stock[i]['open'] < stock[i]['close']: + return "MORNINGSTAR_" + return "" + + def checkEveningstar(self, stock, i): + # 상승 추세에서 저녁별형인지 체크 + if i > 3: + # 상승 추세이고 + if stock[i-2]['close'] < stock[i-1]['close']: + # 어제 양봉인지 체크 + if stock[i-1]['open'] < stock[i-1]['close']: + # 오늘 저녁별형인지 체크 + # 어제 갭 체크 + if stock[i-2]['close'] < stock[i-1]['open'] and stock[i-2]['close'] < stock[i-1]['close']: + # 오늘 시가가 어제 종가보다 낮으며 음봉 + if stock[i]['close'] < stock[i-1]['open'] < stock[i-1]['close']: + return "EVENINGSTAR_" + return "" + def checkAllUpperCross(self, stock, i): if i > 10: @@ -229,21 +414,6 @@ class Common: return "STOCHASTIC#2_" 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 top < stock[i]['close']: - return "highest_" - return "" - def check_Dolpa_Jiji(self, stock, i, day='20'): upper_index = 0 if len(stock) > 5: diff --git a/stockpredictor/analysis/Common_1.py b/stockpredictor/analysis/Common_1.py new file mode 100644 index 0000000..05d9dd9 --- /dev/null +++ b/stockpredictor/analysis/Common_1.py @@ -0,0 +1,364 @@ + +class Common: + + # 상향 + def checkUpward(self, type, data): + check = True + if type != None: + for i in range(len(data)-1): + # 만약 이전이 이후보다 크다면, 상승이 아님 + if data[i][type] > data[i+1][type]: + check = False + break + else: + for i in range(len(data)-1): + # 만약 이전이 이후보다 크다면, 상승이 아님 + if data[i] > data[i+1]: + check = False + break + return check + + # 하향 + def checkDownward(self, type, data): + check = True + for i in range(len(data)-1): + # 만약 이전이 이후보다 작다면, 하락이 아님 + if data[i][type] < data[i+1][type]: + check = False + break + return check + + # 상향 돌파 + def checkUpwardBreakthrough(self, type1, type2, data): + if (type1 in data[0] and type1 in data[1] and type1 in data[2] and + type2 in data[0] and type2 in data[1] and type2 in data[2]): + + if ((data[0][type1] < data[1][type1] < data[2][type1]) and + (data[0][type1] < data[0][type2] and data[2][type1] > data[2][type2])): + return True + return False + + # 하향 돌파 + def checkDownwardBreakthrough(self, type1, type2, data): + if (type1 in data[0] and type1 in data[1] and type1 in data[2] and + type2 in data[0] and type2 in data[1] and type2 in data[2]): + + if ((data[0][type1] > data[1][type1] > data[2][type1]) and + (data[0][type1] > data[0][type2] and data[2][type1] < data[2][type2])): + return True + return False + + + def getStochasticScore(self, stock, i): + score = 0 + + if (stock[i - 1]['slow_k'] < stock[i]['slow_k'] and + stock[i]['slow_d'] < stock[i]['slow_k']): + if stock[i]['slow_k'] < 5: + score = 8 + elif 5 <= stock[i]['slow_k'] < 10: + score = 7 + elif 10 <= stock[i]['slow_k'] < 15: + score = 6 + elif 15 <= stock[i]['slow_k'] < 20: + score = 5 + elif 20 <= stock[i]['slow_k'] < 30: + score = 4 + elif 30 <= stock[i]['slow_k'] < 40: + score = 3 + elif 40 <= stock[i]['slow_k'] < 50: + score = 2 + else: + score = 1 + + if (stock[i - 1]['slow_k'] > stock[i]['slow_k'] and + stock[i - 1]['slow_k'] > stock[i - 1]['slow_d'] and + stock[i]['slow_k'] < stock[i]['slow_d']): + if stock[i]['slow_k'] > 90: + score = -6 + elif 90 >= stock[i]['slow_k'] > 80: + score = -5 + elif 80 >= stock[i]['slow_k'] > 70: + score = -4 + elif 70 >= stock[i]['slow_k'] > 60: + score = -3 + elif 60 >= stock[i]['slow_k'] > 50: + score = -2 + else: + score = -1 + + return score + + def getIchimokuCloudScore(self, stock, i): + score = 0 + + if stock[i - 1]['leadingSpan1'] != 0 and stock[i - 1]['leadingSpan2'] != 0: + + # 후행스팬 > 선행스펜 일때, 후행스펜 > 어제 주가 > 선행스팬 이고, 오늘 주가 > 후행스팬 < 선행스팬 이라면, 매수 2점 + if (stock[i - 1]['leadingSpan2'] > stock[i - 1]['leadingSpan1'] and stock[i]['leadingSpan2'] > stock[i]['leadingSpan1']): + if (stock[i - 1]['leadingSpan2'] > stock[i - 1]['close'] > stock[i - 1]['leadingSpan1'] and + stock[i]['close'] > stock[i]['leadingSpan2'] > stock[i - 1]['leadingSpan1']): + score = 2 + + # 후행스팬 > 선행스펜 일때, 후행스펜 > 선행스팬 > 어제 주가 이고, 오늘 주가 > 후행스팬 < 선행스팬 이라면, 매수 4점 + if (stock[i - 1]['leadingSpan2'] > stock[i - 1]['leadingSpan1'] and stock[i]['leadingSpan2'] > stock[i]['leadingSpan1']): + if (stock[i - 1]['leadingSpan2'] > stock[i - 1]['leadingSpan1'] > stock[i - 1]['close'] and + stock[i]['close'] > stock[i]['leadingSpan2'] > stock[i - 1]['leadingSpan1']): + score = 4 + + # 선행스팬 > 후행스팬 일때, 선행스팬 > 어제 주가 > 후행스팬 이고, 오늘 주가 > 선행스팬 < 후행스팬 이라면, 매수 1점 + if (stock[i - 1]['leadingSpan1'] > stock[i - 1]['leadingSpan2'] and stock[i]['leadingSpan1'] > stock[i]['leadingSpan2']): + if (stock[i - 1]['leadingSpan1'] > stock[i - 1]['close'] > stock[i - 1]['leadingSpan2'] and + stock[i]['close'] > stock[i]['leadingSpan1'] > stock[i - 1]['leadingSpan2']): + score = 1 + + # 선행스팬 > 후행스팬 일때, 선행스팬 > 후행스팬 > 어제 주가 이고, 오늘 주가 > 선행스팬 < 후행스팬 이라면, 매수 3점 + if (stock[i - 1]['leadingSpan1'] > stock[i - 1]['leadingSpan2'] and stock[i]['leadingSpan1'] > stock[i]['leadingSpan2']): + if (stock[i - 1]['leadingSpan1'] > stock[i - 1]['leadingSpan2'] > stock[i - 1]['close'] and + stock[i]['close'] > stock[i]['leadingSpan1'] > stock[i - 1]['leadingSpan2']): + score = 3 + + # 어제는 주가가 선행이나 후행스팬 위에 있었지만, 오늘은 두 스팬 모두 아래로 내려왔을 때 매도 + if (stock[i - 1]['close'] > stock[i - 1]['leadingSpan1'] or stock[i - 1]['close'] > stock[i - 1]['leadingSpan2']): + if (stock[i]['close'] < stock[i]['leadingSpan1'] and stock[i]['close'] < stock[i]['leadingSpan2']): + score = -1 + + return score + + def checkLongYangBongAfterUmBong(self, stock, i): + if i > 0: + if stock[i-1]['open'] > stock[i-1]['close']: # 어제가 음봉인지 체크 + if stock[i]['open'] < stock[i]['close'] and stock[i]['close'] == stock[i]['high']: # 오늘 장대양봉인지 체크 + if stock[i-1]['volume']*2 < stock[i]['volume']: # 어제 거래량 보다 두배 이상일 때 + return True + return False + + def checkAllUpperCross(self, stock, i): + if i > 10: + if stock[i]['avg5'] < stock[i]['close'] and stock[i]['avg20'] < stock[i]['close'] and stock[i]['avg60'] < stock[i]['close'] and stock[i]['avg120'] < stock[i]['close']: + for j in range(1, 6): + if stock[i-j]['close'] < stock[i-j]['avg5'] and stock[i-j]['close'] < stock[i-j]['avg20'] and stock[i-j]['close'] < stock[i-j]['avg60'] and stock[i-j]['close'] < stock[i-j]['avg120']: + return "ALLUPPER_" + return "" + + def check_golded_cross(self, stock, i): + if i > 1: + # 60 -> 120 + # 오늘 지수는 120 < 60 < 20 < 5 + # 어제 지수는 60 < 120 이었다. + # 60, 20, 5일선 모두 어제 보다 오늘이 더 높다 (상승중) + # 5일과 20일선은 상승 중이며, 60일선이 120일 선을 뚫고 올라온 순간인지 체크함 (삼성전자 2021-07-29) + # 이때 바로 매수하지 않는다. + # 이 시점 이후로 5일선이 20일선을 하방으로 뚫었다가 다시 20일선을 상방으로 뚫는 순간 매수를 시도한다. + if stock[i]['avg120'] < stock[i]['avg60'] < stock[i]['avg20'] < stock[i]['avg5']: + if stock[i-1]['avg120'] > stock[i-1]['avg60']: + if (stock[i-1]['avg60'] < stock[i]['avg60'] and stock[i-1]['avg20'] < stock[i]['avg20'] and stock[i-1]['avg5'] < stock[i]['avg5']): + return "GOLDEN#1_" + + # 20 -> 120: 5일과 20일, 60일선은 상승 중이며, 20일선이 120일 선을 뚫고 올라온 순간인지 체크 (SK 2021-12-09, 나노스 2021-02-04) + # 어제는 60일선 < 20일선 < 120일선 < 5일선이지만, 오늘은 60일선 < 120일선 < 20일선 < 5일선 + # 이때 바로 매수하지 않는다. + # 이 시점 이후로 5일선이 20일선을 하방으로 뚫었다가 다시 20일선을 상방으로 뚫는 순간 매수를 시도한다. + if stock[i]['avg60'] < stock[i]['avg120'] < stock[i]['avg20'] < stock[i]['avg5']: + if stock[i-1]['avg60'] < stock[i-1]['avg20'] < stock[i]['avg120'] < stock[i]['avg5']: + if (stock[i-1]['avg60'] < stock[i]['avg60'] and stock[i-1]['avg20'] < stock[i]['avg20'] and stock[i-1]['avg5'] < stock[i]['avg5']): + return "GOLDEN#2_" + + # 20 -> 120: 5일과 20일, 60일선은 상승 중이며, 20일선이 120일 선을 뚫고 올라온 순간인지 체크 (갤럭시아머니트리 2021-02-08) + # 어제는 60일선 < 120일선 < 5일선 < 20일선이지만, 오늘은 60일선 < 120일선 < 20일선 < 5일선 + if stock[i]['avg60'] < stock[i]['avg120'] < stock[i]['avg20'] < stock[i]['avg5']: + if stock[i-1]['avg60'] < stock[i-1]['avg20'] < stock[i]['avg120'] < stock[i]['avg5']: + if (stock[i-1]['avg60'] < stock[i]['avg60'] and stock[i-1]['avg20'] < stock[i]['avg20'] and stock[i-1]['avg5'] < stock[i]['avg5']): + return "GOLDEN#3_" + + return "" + + def check_bearmarket_buying(self, stock, stochastic, i): + if i > 1: + # 5일선 상승 시점 확인 (SK 2020년 3월 24일) + # 어제는 5일선 < 20일선 < 120일선 < 60일선이며, 오늘은 20일선 < 120일선 < 60일선 + # 어제와 오늘 모두 20일, 60일, 120일선은 모두 하락이다. + # 어제 종가보다 오늘 종가가 높고, 종가는 5일선 위에 올라왔다. + # 오늘 slow_k는 30 이하이며, 어제는 slow_d가 높았지만, 오늘은 slow_k가 더 높음 + if (stock[i-1]['avg5'] < stock[i-1]['avg20'] < stock[i-1]['avg120'] < stock[i]['avg60']) and (stock[i]['avg20'] < stock[i-1]['avg120'] < stock[i]['avg60']): + if stock[i]['avg120'] < stock[i-1]['avg120'] and stock[i]['avg60'] < stock[i-1]['avg60'] and stock[i]['avg20'] < stock[i-1]['avg20']: + if stock[i-1]['close'] <= stock[i]['close'] and stock[i]['avg5'] <= stock[i]['close']: + if (stochastic[i]['slow_k'] < 30 and (stochastic[i-1]['slow_k'] < stochastic[i-1]['slow_d'] and stochastic[i]['slow_d'] < stochastic[i]['slow_k'])): + return "BEARMARKET#1_" + + # 5일선 상승 시점 확인 (원풍물산 2020년 3월 24일, NHN한국사이버결제 2018년 11월 2일) + # 어제는 5일선 < 20일선 < 60일선 < 120일선이며, 오늘은 20일선 < 60일선 < 120일선 + # 어제와 오늘 모두 20일, 60일, 120일선은 모두 하락이다. + # 어제 종가보다 오늘 종가가 높고, 종가는 5일선 위에 올라왔다. + # 오늘 slow_k는 30 이하이며, 어제는 slow_d가 높았지만, 오늘은 slow_k가 더 높음 + if (stock[i-1]['avg5'] < stock[i-1]['avg20'] < stock[i-1]['avg60'] < stock[i]['avg120']) and (stock[i]['avg20'] < stock[i-1]['avg60'] < stock[i]['avg120']): + if stock[i]['avg120'] < stock[i-1]['avg120'] and stock[i]['avg60'] < stock[i-1]['avg60'] and stock[i]['avg20'] < stock[i-1]['avg20']: + if stock[i-1]['close'] <= stock[i]['close'] and stock[i]['avg5'] <= stock[i]['close']: + if (stochastic[i]['slow_k'] < 30 and (stochastic[i-1]['slow_k'] < stochastic[i-1]['slow_d'] and stochastic[i]['slow_d'] < stochastic[i]['slow_k'])): + return "BEARMARKET#2_" + return "" + + def check_stochastic(self, stock, stochastic, i): + if i > 2: + # 스토케스틱이 15 이하인 경우 + # 어제보다 slow_k가 상승했고, 오늘 slow_k가 slow_d 위에 있는 경우, + if stochastic[i]['slow_k'] < 15: + if stochastic[i-1]['slow_k'] < stochastic[i]['slow_k'] and stochastic[i]['slow_d'] < stochastic[i]['slow_k']: + return "STOCHASTIC_" + return "" + + def check_stochastic_buying(self, stock, stochastic, ichimoku, i): + if i > 3: + # 삼성전자 2020년 11월 4일 + # 어제는 slow_K가 Slow_d 아래였지만, 오늘은 slow_K가 Slow_d 보다 높다. + # 에제의 slow_k는 20보다 작고, 오늘의 slow_K는 30보다 작다 + # 1일전이나, 2, 3일전의 종가가 일목균형표 내의 선행스팬1 아래 존재하며,오늘 고가는 선행스팬1 위에 존재한다. + # 그저께 시가보다 어제의 시가가, 어제의 시가보다는 오늘의 시가가 높다. + if (stochastic[i-1]['slow_k'] < stochastic[i-1]['slow_d'] and stochastic[i]['slow_d'] < stochastic[i]['slow_k']): + if (stochastic[i - 1]['slow_k'] < 20 and stochastic[i]['slow_k'] < 30): + if ((stock[i-3]['close'] < ichimoku[i-3]['leadingSpan1'] or stock[i-2]['close'] < ichimoku[i-2]['leadingSpan1'] or stock[i-1]['close'] < ichimoku[i-1]['leadingSpan1']) and ichimoku[i-1]['leadingSpan1'] < stock[i-1]['high']): + if stock[i-2]['open'] < stock[i-1]['open'] < stock[i]['open']: + return "STOCHASTIC#1_" + + # 스토케스틱이 15 이하인 경우 + # 어제보다 slow_k가 상승했고, 오늘 slow_k가 slow_d 위에 있는 경우, + # 오늘 종가가 5일선 위에 있는 경우 + if stochastic[i]['slow_k'] < 15: + if stochastic[i - 1]['slow_k'] < stochastic[i]['slow_k'] and stochastic[i]['slow_d'] < stochastic[i]['slow_k']: + if stock[i]['avg5'] < stock[i]['close']: + return "STOCHASTIC#2_" + 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 top < stock[i]['close']: + return "highest_" + 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: + 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, 61): + if stock[i-j]['avg20'] < stock[i-j]['avg5']: + index1 = j + break + 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 + return "5-20_" + return "" + + def check_Danta1(self, stock, i): + """ + 어제 상한가 혹은 상승양봉이 나온다. + 오늘 상승 출발을 해야 하며 상승 음봉이 나온다 + - 어제 종가 = 어제 상한가 < 종가 < 시가 < 상한가 + https://docs.google.com/presentation/d/1MVuaeRNljqLCdn4dPZmvVdtl2Ab09Zwg/edit#slide=id.gc7b796e645_0_109 + + 만약 다음날 시작초가가 오늘 종가보다 높게 상승으로 출발한다면 매수를 한다. + 손절가는 오늘 최저가이다. + """ + 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_Danta2(self, stock, i): + """ + 쐐기, 수렴, 깃대 패턴 확인 + # https://docs.google.com/presentation/d/1MVuaeRNljqLCdn4dPZmvVdtl2Ab09Zwg/edit#slide=id.gc7b796e645_0_144 + + 상단 추세선을 돌파하면 매수를 한다. + """ + 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_RightArrange(self, stock, i): + """ + 어제는 정배열이 아니었는데, 오늘은 정배열인 경우 + """ + 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_W1Rise(self, stock, i, limit): + if len(stock) > 5: + rate = round((stock[i]["close"] - stock[i-4]["close"]) / stock[i-4]["close"],2) + if rate >= limit: + return "1w("+str(rate)+")_" + return "" + + def check_D1Fall(self, stock, i, limit): + if len(stock) > 2: + # 1000, 900, (900 - 1000) / 900 = -0.111 + # 1000, 800, (800 - 1000) / 800 = -0.25 + rate = round((stock[i]["close"] - stock[i-1]["close"]) / stock[i-1]["close"], 2) + if rate <= limit: + return "1d("+str(rate)+")_" + return "" \ No newline at end of file diff --git a/stockpredictor/crawler/toSQLite/Crawler.py b/stockpredictor/crawler/toSQLite/Crawler.py index ae34084..2892812 100644 --- a/stockpredictor/crawler/toSQLite/Crawler.py +++ b/stockpredictor/crawler/toSQLite/Crawler.py @@ -53,13 +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