Files
DeepStock/stockpredictor/analysis/Analyzer.py
dsyoon 9af08dbee2 init
2021-02-18 02:14:36 +09:00

535 lines
22 KiB
Python

import json
import os
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
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
macd = None
rsi = None
stochastic = None
ichimokuCloud = 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.macd = MACD()
self.rsi = RSI()
self.stochastic = Stochastic()
self.ichimokuCloud = IchimokuCloud()
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):
if (data[year1]['영업이익'] > 0 and data[year1]['당기순이익'] > 0):
self.fnguide[result[0]] = True
if (year2 in data):
if (data[year2]['영업이익'] > 0 and data[year2]['당기순이익'] > 0):
self.fnguide[result[0]] = True
if (year3 in data):
if (data[year3]['영업이익'] > 0 and data[year3]['당기순이익'] > 0):
self.fnguide[result[0]] = True
else:
self.fnguide[result[0]] = False
else:
if (data[year1]['영업이익'] > data[year2]['영업이익']):
self.fnguide[result[0]] = True
else:
self.fnguide[result[0]] = False
else:
self.fnguide[result[0]] = False
else:
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_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=5, cols=1, subplot_titles=('MACD', 'Stochastic', 'RSI', '거래량', '일목균형표'))
for trace in macd_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)
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 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()
# 기존 분석 데이터를 모두 지움
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 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):
"""
[매도]
1. MACD
1) MACD가 시그널설을 하향 돌파하면 매도한다.
2) MACD가 기준선 (0) 아래에 있는 한 주가는 하향추세이거나 또는 상승하지 않는다.
3) 시그널 추세가 하향인 한 매수 신호가 나올 때까지 주식을 보유하지 않는다.
4) 하락형 다이버전스가 발생하면 적극 매도를 검토한다.
2. Stochasic: %K선이 %D선을 하향 돌파하면 매도 신호로 보되 다음 사항들이 일치하면 매도한다.
1) 스토캐스틱 지표가 하락추세를 보이고, 50 이하에 있어야 한다.
2) 스토캐스틱 지표가 고점이 낮아지는 하락파동에 있어야 한다.
3) 주가가 5일 또는 20일 이동 평균선 아래에 있어야 한다.
4) MACD 지표가 하락으로 전환하거나 또는 최소한 상승을 멈추어야 한다.
5) 하락형 다이버전스가 발생하면 매도를 검토한다.
3. rsi
1) rsi가 하향이고 70이하로 떨어지면 매도,
2) rsi가 하향이고 50이하로 떨어지면 매도,
3) rsi가 하향이고 30이하로 떨어지면 단기매도,
[매수]
1. MACD
1) MACD가 시그널설을 상향 돌파하면 매수한다.
2) MACD가 기준선 (0) 위에 있는 한 주가는 상승추세이거나 또는 하락하지 않는다.
3) 시그널 추세가 상승하는 한 매도 신호가 나올 때까지 주식을 보유한다.
4) 상승형 다이버전스가 발생하면 적극 매수를 검토한다.
2. Stochasic: %K선이 %D선을 상향 돌파하면 매수 신호로 보되 다음 사항들이 일치하면 매수한다.
1) 스토캐스틱 지표가 상승추세를 보이고, 50 이상에 있어야 한다.
2) 스토캐스틱 지표가 저점을 높이는 상승파동에 있어야 한다.
3) 주가가 5일 또는 20일 이동 평균선 위에 있어야 한다.
4) MACD 지표가 상승으로 전환하거나 또는 최소한 하락을 멈추어야 한다.
5) 상승형 다이버전스가 발생하면 매수를 검토한다.
3. rsi
1) 상향이고 30을 돌파하면 매수,
2) rsi가 상향이고 40을 돌파하면 매수,
3) rsi가 상향이고 70을 돌파하면 단기매수,
"""
i = last_index
# 매수금액을 구
# 이전 3일 동안의 어제종가-오늘저가의 평균을 구함 --> (종가-시가)/3
# 그래서 오늘 종가에 구한 평균값을 더해서 내일 종목을 매수함
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:
buy_price = round(STOCK[i]['close'] - (buy_price/count))
stochastic_score = self.common.getStochasticScore(STOCHASTIC, i)
"""
if STOCK[i]['volume'] > 10000:
if MACD[i - 1]['macd'] < MACD[i]['macd']:
if MACD[i - 1]['macd'] < MACD[i - 1]['macds'] and MACD[i]['macd'] > MACD[i]['macds']:
return True,buy_price, stochastic_score
if stochastic_score > 0:
return True, buy_price, stochastic_score
"""
if STOCHASTIC[i]['slow_k'] < 10 and self.common.checkLongYangBongAfterUmBong(STOCK, i):
return 'STOCHASTIC_YANGBONG', buy_price
if STOCHASTIC[i]['slow_k'] < 10:
return 'STOCHASTIC', buy_price
if self.common.checkLongYangBongAfterUmBong(STOCK, i):
return 'YANGBONG', buy_price
return "", buy_price
def analyzeToFile(self, outFileName):
conn = sqlite3.connect(self.inFileName)
cursor = conn.cursor()
outfp = open(outFileName, "w", encoding="utf-8")
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])}
macd = json.loads(result[3])
stochastic = json.loads(result[4])
ichimokuCloud = json.loads(result[5])
rsi = json.loads(result[6])
last_index = self.get_last_index(stock)
lastStock = stock['PRICE']
state, buy_price = self.analyzeFinalScore(last_index, lastStock, macd, stochastic, ichimokuCloud, rsi)
if state != "":
# self.macd.draw(stock)
print(stock['CODE'], stock['NAME'], str(buy_price), stochastic[last_index]['slow_k'], macd[last_index]['macd'], rsi[last_index]['rsi_buy'], ichimokuCloud[last_index]['ichimoku_buy'])
outfp.write("%s\t%s\t%s\t%d\t%s\t%s\t%s\n"%(stock['CODE'], stock['NAME'], str(buy_price), stochastic[last_index]['slow_k'], rsi[last_index]['rsi_buy'], macd[last_index]['macd'], ichimokuCloud[last_index]['ichimoku_buy']))
print("#file", rowid, stock['NAME'])
rowid += 1
cursor.execute('SELECT * FROM ' + self.tableName + ' WHERE rowid=?', (rowid,))
result = cursor.fetchone()
cursor.close()
conn.close()
outfp.close()
return
# 그래프 출력
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]
"""
if (item_code in self.fnguide and not self.fnguide[item_code]):
rowid += 1
cursor.execute('SELECT * 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])}
last_index = self.get_last_index(stock)
STOCK = stock['PRICE']
MACD = stock['MACD']
STOCHASTIC = stock['STOCHASTIC']
ICHIMOKU = stock['ICHIMOKU']
RSI = stock['RSI']
state, buy_price = self.analyzeFinalScore(last_index, STOCK, MACD, STOCHASTIC, ICHIMOKU, RSI)
stochastic_score = STOCHASTIC[last_index]['slow_k']
macd_score = MACD[last_index]['macd']
rsi_score = RSI[last_index]['rsi']
ichimoku_score = ICHIMOKU[last_index]['ichimoku_buy']
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)
fig['layout'].update(title=title)
fileName = "%s/%s__%.3f__%.3f__%s.html" % (outPath, state, stochastic_score, rsi_score, item_name.replace(" ", ""))
po.write_html(fig, file=fileName, auto_open=False)
else:
if RSI[last_index]['rsi_buy'] == 1 and STOCK[last_index]['volume'] > 10000:
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)
fig['layout'].update(title=title)
fileName = "%s/%.3f__%.3f__%s.html"%(tmp_path, stochastic_score, rsi_score, item_name.replace(" ", ""))
po.write_html(fig, file=fileName, auto_open=False)
print ("#html", rowid, stock['NAME'])
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 ICHIMOKU = "", MACD = "", STOCHASTIC = "", RSI = ""')
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_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
cursor.execute('SELECT * FROM ' + self.tableName + ' WHERE rowid=?', (rowid,))
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"]))
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__":
PROJECT_HOME = "../.."
inFileName = PROJECT_HOME + '/resources/stock.db'
inFnguideFileName = PROJECT_HOME + '/resources/fnguide.db'
analyzer = Analyzer(PROJECT_HOME, inFileName, inFnguideFileName)
# 분석 & update DB
"""
#print ("analyze IchimokuCloud...")
analyzer.analyzeIchimokuCloud()
#print ("analyze MACD...")
analyzer.analyzeMACD()
#print ("analyze Stochastic...")
analyzer.analyzeStochastic()
#print ("analyze RSI...")
analyzer.analyzeRSI()
"""
###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("done...")