diff --git a/stockpredictor/analysis/AnalyzerSqlite.py b/stockpredictor/analysis/AnalyzerSqlite.py index be0c47b..7ab21a4 100644 --- a/stockpredictor/analysis/AnalyzerSqlite.py +++ b/stockpredictor/analysis/AnalyzerSqlite.py @@ -1,4 +1,3 @@ -import json import os import time import shutil @@ -11,7 +10,6 @@ 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 @@ -31,6 +29,9 @@ class AnalyzerSqlite: bolingerBand = None ichimokuCloud = None + top500 = None + fnguide = None + common = None stockFileName = None fnguideFileName = None @@ -38,8 +39,6 @@ class AnalyzerSqlite: moving_avg = None - fnguide = {} - def __init__(self, PROJECT_HOME, stockFileName, fnguideFileName): self.PROJECT_HOME = PROJECT_HOME self.stockFileName = stockFileName @@ -51,10 +50,29 @@ class AnalyzerSqlite: self.bolingerBand = BolingerBand() self.ichimokuCloud = IchimokuCloud() + self.top500 = self.getTop500(fnguideFileName) + self.fnguide = self.readFnguide(fnguideFileName) + return - def readFnguide(self, code): - conn = sqlite3.connect(self.fnguideFileName) + def getTop500(self, fnguideFileName): + conn = sqlite3.connect(fnguideFileName) + cursor = conn.cursor() + + sql = "select DISTINCT CODE, NAME from fnguide order by total_ownership_interest desc limit 500" + cursor.execute(sql) + result = cursor.fetchall() + + top500 = {} + for idx, item in enumerate(result): + top500[item[0]] = (idx+1, item[1]) + + cursor.close() + conn.close() + return top500 + + def readFnguide(self, fnguideFileName): + conn = sqlite3.connect(fnguideFileName) cursor = conn.cursor() today = datetime.today() @@ -62,37 +80,34 @@ class AnalyzerSqlite: year2 = str(today.year - 2) + ".12.01" year3 = str(today.year - 3) + ".12.01" - sql = "SELECT business_profits, business_profits_ratio, debt_ratio, ROA, ROE, EPS, BPS, DPS, PER, PBR FROM fnguide " - sql += " WHERE code=? and (ymd=? or ymd=? or ymd=?) and type=''" - sql += " order by ymd desc" - cursor.execute(sql, (code,year1,year2,year3)) - result = cursor.fetchone() + sql = "SELECT CODE, NAME, ymd, business_profits, business_profits_ratio, debt_ratio, ROA, ROE, EPS, BPS, DPS, PER, PBR FROM fnguide " + sql += " WHERE (ymd=? or ymd=? or ymd=?) and type=''" + sql += " order by code, ymd desc" + cursor.execute(sql, (year1,year2,year3)) + result = cursor.fetchall() - business_profits, business_profits_ratio, debt_ratio, ROA, ROE, EPS, BPS, DPS, PER, PBR = [], [], [], [], [], [], [], [], [], [] + fnguide = {} for item in result: - business_profits.append(item[0]) - business_profits_ratio.append(item[1]) - debt_ratio.append(item[2]) - ROA.append(item[3]) - ROE.append(item[4]) - EPS.append(item[5]) - BPS.append(item[6]) - DPS.append(item[7]) - PER.append(item[8]) - PBR.append(item[9]) + if item[0] not in fnguide: + fnguide[item[0]] = [] + + fnguide[item[0]].append( + {'NAME': item[1], + 'ymd': item[2], + 'business_profits': item[3], + 'business_profits_ratio': item[4], + 'debt_ratio': item[5], + 'ROA': item[6], + 'ROE': item[7], + 'EPS': item[8], + 'BPS': item[9], + 'DPS': item[10], + 'PER': item[11], + 'PBR': item[12]}) cursor.close() conn.close() - return {'business_profits': business_profits, - 'business_profits_ratio': business_profits_ratio, - 'debt_ratio': debt_ratio, - 'ROA': ROA, - 'ROE': ROE, - 'EPS': EPS, - 'BPS': BPS, - 'DPS': DPS, - 'PER': PER, - 'PBR': PBR} + return fnguide def draw(self, stock): @@ -414,14 +429,26 @@ class AnalyzerSqlite: return - def writeFile(self, type, CODE, NAME, stock, state): - fig = self.draw(stock) - title = "%s (%s), %d %s 차트 (URL1, URL2)" % (NAME, CODE, stock['close'][0], state, CODE, CODE) - fig['layout'].update(title=title) + def writeFile(self, type, CODE, NAME, top, stock, state): + # 3년 이내 한번이라도 영업이익이 났는지 체크를 함 + fnguide = None + if CODE in self.fnguide: + fnguide = self.fnguide[CODE] + check = True + if fnguide: + check = False + for item in fnguide: + if item['business_profits'] > 0: + check = True - fileName = self.outPath + "/" + str(type) - fileName = "%s/%s_%s_%s.html" % (fileName, NAME.replace(" ", ""), CODE, state) - po.write_html(fig, file=fileName, auto_open=False) + if check: + fig = self.draw(stock) + title = "%s (%s), %d %s 차트 (URL1, URL2)" % (NAME, CODE, stock['close'][0], state, CODE, CODE) + fig['layout'].update(title=title) + + fileName = self.outPath + "/" + str(type) + fileName = "%s/%s_%s_%s_%s.html" % (fileName, top, NAME.replace(" ", ""), CODE, state) + po.write_html(fig, file=fileName, auto_open=False) return def checkVolume(self, p_volume, volume): @@ -464,6 +491,10 @@ class AnalyzerSqlite: NAME = item[1] print (idx, CODE, NAME) + top = "0" + if CODE in self.top500: + top = str(self.top500[CODE][0]) + conn = sqlite3.connect(self.stockFileName) cursor = conn.cursor() @@ -545,27 +576,27 @@ class AnalyzerSqlite: # 0_스토케스틱이 10 미만 if len(close) > 5 and stochastic_score is not None and stochastic_score < 10: type = "참고_0_스토케스틱이 10 미만" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) # 0_bolingerband 하단 if len(close) > 60 and bolingerband_lower[0] is not None and close[0] < bolingerband_lower[0]: type = "참고_0_bolingerband 하단" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) # 0_260일 위치 에너지가 10% 미만 if len(close) > 5 and positionalEnergy1 is not None and positionalEnergy1 < 0.1: type = "참고_0_260일 위치 에너지가 10% 미만" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) # 0_260일 가격 반토막 이상 if len(close) > 5 and positionalEnergy2 is not None and positionalEnergy2 < 0.5: type = "참고_0_260일 가격 반토막 이상" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) # 0_종가가 240일선 아래라면 매수한다. if close[0] < avg240[0]: type = "참고_0_240일선 아래" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) # 1_기준선 위 전환선 올라옴 if len(close) > 50: @@ -576,7 +607,7 @@ class AnalyzerSqlite: ichimokucloud_changeLine[4] <= ichimokucloud_baseLine[4]) and volume[0] > volume[1]): type = "참고_1_기준선 위 전환선 올라옴" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) # "1_기준선 위 120일선 올라옴" if len(close) > 50: @@ -587,7 +618,7 @@ class AnalyzerSqlite: avg120[4] <= ichimokucloud_baseLine[4]) and volume[0] > volume[1]): type = "참고_1_기준선 위 120일선 올라옴" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) # "1_기준선 위 200일선 올라옴" if len(close) > 50: @@ -598,7 +629,7 @@ class AnalyzerSqlite: avg200[4] <= ichimokucloud_baseLine[4]) and volume[0] > volume[1]): type = "참고_1_기준선 위 200일선 올라옴" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) # "1_기준선 위 240일선 올라옴" if len(close) > 50: @@ -609,59 +640,59 @@ class AnalyzerSqlite: avg240[4] <= ichimokucloud_baseLine[4]) and volume[0] > volume[1]): type = "참고_1_기준선 위 240일선 올라옴" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) # 1_종가가 200일선 돌파 if len(close) > 5 and close[0] >= avg200[0] and close[1] < avg200[1] and close[2] < avg200[2] and close[3] < avg200[3] and close[4] < avg200[4]: type = "참고_1_200일선 돌파" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) # 1_종가가 240일선 돌파 if len(close) > 5 and close[0] >= avg240[0] and close[1] < avg240[1] and close[2] < avg240[2] and close[3] < avg240[3] and close[4] < avg240[4]: type = "참고_1_240일선 돌파" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) # 1_20일선 돌파 temp_status = self.common.check_Dolpa_Jiji(stock, '20') if temp_status != "": type = "참고_1_20일선 돌파" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) # 1_60일선 돌파 temp_status = self.common.check_Dolpa_Jiji(stock, '60') if temp_status != "": type = "참고_1_60일선 돌파" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) # 1_골든크로스 golden_cross_status = self.common.check_golded_cross(stock) if golden_cross_status != "": type = "참고_1_GoldenCross" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) # 1_거래량 5배 이상 if len(volume)>2 and volume[0] > volume[1]*10: type = "참고_1_거래량 10배 이상" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) # 1_bolingerband 하단 돌파 상승 if (len(close) > 60 and (bolingerband_lower[0] is not None and bolingerband_lower[1] is not None) and close[0] > bolingerband_lower[0] and close[1] < bolingerband_lower[1]): type = "참고_1_bolingerband 하단 돌파 상승" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) # 1_정배열 right_arrange = self.common.check_RightArrange(stock) if right_arrange != "": type = "참고_1_정배열" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) # 1_모든 라인 돌파 if (len(close) > 50 and close[0] > max(open[0], avg5[0], avg20[0], avg60[0], avg120[0], avg240[0], bolingerband_upper[0], ichimokucloud_changeLine[0], ichimokucloud_baseLine[0]) and open[0] < max(open[0], avg5[0], avg20[0], avg60[0], avg120[0], avg240[0], bolingerband_upper[0], ichimokucloud_changeLine[0], ichimokucloud_baseLine[0])): type = "참고_1_모든 라인 돌파" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) ### 코스피 지수 기준 숏 전략: # 캔들이 전환선 붕괴시키면 1을 매수한다. @@ -674,33 +705,33 @@ class AnalyzerSqlite: if (len(close) > 50 and close[1] < ichimokucloud_changeLine[1] and ichimokucloud_changeLine[0] < close[0]): type = "1_캔들_전환선_위로_올라옴" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) if (len(close) > 50 and close[1] < ichimokucloud_baseLine[1] and ichimokucloud_baseLine[0] < close[0]): type = "2_캔들_기준선_위로_올라옴" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) if (len(close) > 50 and close[0] < close[26] and close[25] < close[0]): type = "3_후행스팬_캔들_위로_올라옴" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) if (len(close) > 50 and close[1] > ichimokucloud_changeLine[1] and ichimokucloud_changeLine[0] > close[0]): type = "-1_캔들_전환선_아래로_내려옴" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) if (len(close) > 50 and close[1] > ichimokucloud_baseLine[1] and ichimokucloud_baseLine[0] > close[0]): type = "-2_캔들_기준선_아래로_내려옴" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) if (len(close) > 50 and close[0] > close[26] and close[25] > close[0]): type = "-3_후행스팬_캔들_아래로_내려옴" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) if (len(close) > 2 and close[1] < close[0] and open[0] < close[0] and self.checkVolume(volume[1], volume[0])): type = "1_거래량_상승" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) if (len(close) > covid_low_ymd_index and close[0] > close[covid_low_ymd_index]*0.8 and close[0] < close[covid_low_ymd_index]*1.1): type = "1_코로나_근접" - self.writeFile(type, CODE, NAME, stock, state) + self.writeFile(type, CODE, NAME, top, stock, state) return @@ -759,6 +790,7 @@ class AnalyzerSqlite: stock = {"CODE": item[0], "NAME": item[1], "PRICE":[]} print("# :", rowid, ", CODE: ", stock['CODE'], ", NAME: ", stock['NAME']) + sql = 'SELECT ymd, close, diff, open, high, low, volume FROM ' + stockTableName + ' where CODE=? order by ymd' cursor.execute(sql, (stock['CODE'],)) items = cursor.fetchall()