This commit is contained in:
dsyoon
2021-07-16 21:48:16 +09:00
parent 56c3e364d7
commit 86bb1b7bdd
6 changed files with 67 additions and 799 deletions

View File

@@ -4,6 +4,7 @@ import time
import shutil
from stockpredictor.analysis.Common import Common
from stockpredictor.analysis.Stochastic import Stochastic
from stockpredictor.analysis.BolingerBand import BolingerBand
import matplotlib.pyplot as plt
import datetime
import sqlite3
@@ -45,6 +46,7 @@ class Analyzer:
self.common = Common()
self.stochastic = Stochastic()
self.bolingerBand = BolingerBand()
self.readFnguide()
return
@@ -459,7 +461,7 @@ class Analyzer:
cursor = conn.cursor()
# 기존 분석 데이터를 모두 지움
cursor.execute('update ' + self.tableName + ' set STOCHASTIC = ""')
cursor.execute('update ' + self.tableName + ' set STOCHASTIC = "", BOLINGERBAND = ""')
rowid = 1
cursor.execute('SELECT * FROM ' + self.tableName + ' WHERE rowid=?', (rowid,))
@@ -470,6 +472,9 @@ class Analyzer:
try:
results_STOCHASTIC = self.stochastic.analyze(stock)
text_STOCHASTIC = json.dumps(results_STOCHASTIC, ensure_ascii=False)
results_BolingerBand = self.bolingerBand.analyze(stock)
text_BOLINGERBAND = json.dumps(results_BolingerBand, ensure_ascii=False)
except:
print("#", rowid, stock['NAME'])
rowid += 1
@@ -477,7 +482,7 @@ class Analyzer:
result = cursor.fetchone()
continue
cursor.execute("UPDATE " + self.tableName + " SET STOCHASTIC=? WHERE CODE=?", (text_STOCHASTIC, stock["CODE"]))
cursor.execute("UPDATE " + self.tableName + " SET STOCHASTIC=?, BOLINGERBAND=? WHERE CODE=?", (text_STOCHASTIC, text_BOLINGERBAND, stock["CODE"]))
print("#", rowid, stock['NAME'])
rowid += 1
cursor.execute('SELECT * FROM ' + self.tableName + ' WHERE rowid=?', (rowid,))
@@ -503,7 +508,7 @@ if __name__ == "__main__":
analyzer.analyzeStochastic()
"""
###analyzer.analyze()
analyzer.analyze()
day = datetime.today().strftime("%Y%m%d")

View File

@@ -1,432 +0,0 @@
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...")

View File

@@ -0,0 +1,54 @@
import pandas as pd
from stockpredictor.analysis.Common import Common
import plotly.graph_objs as go
from plotly import tools, subplots
import plotly.io as po
class BolingerBand:
common = None
def __init__(self):
self.common = Common()
return
def apply(self, df, n=10, m=6, t=6):
# 입력받은 값이 dataframe이라는 것을 정의해줌
df = pd.DataFrame(df)
max20 = df["close"].rolling(window=20).mean()
stddev = df["close"].rolling(window=20).std()
upper = max20 + (stddev * 2) # 상단 볼리저 밴드
lower = max20 - (stddev * 2) # 하단 볼리저 밴드
middle = (upper + lower ) / 2
# dataframe에 컬럼 추가
#df = df.assign(fast_k=fast_k, slow_k=slow_k, slow_d=slow_d).dropna()
df = df.assign(upper=upper, middle=middle, lower=lower)
return df
def analyze(self, stock):
df = pd.DataFrame()
df = df.from_dict(stock['PRICE'])
df = self.apply(df)
for i in range(len(df.upper)):
stock['PRICE'][i]['upper'] = df.upper.values[i]
stock['PRICE'][i]['middle'] = df.middle.values[i]
stock['PRICE'][i]['lower'] = df.lower.values[i]
# 0: 중립, 1: 매수, -1: 매도
stock['PRICE'][i]['bolingerband_buy'] = 0
if i > 0:
stock['PRICE'][i]['bolingerband_buy'] = self.common.getBolingerBandScore(stock['PRICE'], i)
results = []
for day in stock['PRICE']:
results.append({'DATE': day['DATE'],
'upper': day['upper'],
'middle': day['middle'],
'lower': day['lower'],
'bolingerband_buy': day['bolingerband_buy']})
return results

View File

@@ -89,6 +89,9 @@ class Common:
return score
def getBolingerBandScore(self, stock, i):
return 0
def getIchimokuCloudScore(self, stock, i):
score = 0

View File

@@ -1,364 +0,0 @@
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 ""

View File

@@ -0,0 +1,2 @@
# https://grand-unified-engine.tistory.com/21
# https://github.com/FinanceData/FinanceDataReader