This commit is contained in:
dosangyoon
2022-02-02 05:36:55 +09:00
parent 2d4f759ab6
commit 198169493b
15 changed files with 3260 additions and 315 deletions

View File

Can't render this file because it is too large.

View File

@@ -0,0 +1,712 @@
import json
import os
import time
import shutil
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
from stockpredictor.analysis.Common import Common
from stockpredictor.analysis.Stochastic import Stochastic
from stockpredictor.analysis.BolingerBand import BolingerBand
from stockpredictor.analysis.IchimokuCloud import IchimokuCloud
from stockpredictor.crawler.sQLite.MovingAverage import MovingAverage
class AnalyzerSqlite:
PROJECT_HOME = None
stochastic = None
bolingerBand = None
ichimokuCloud = None
common = None
stockFileName = None
fnguideFileName = None
analyzedFileName = None
moving_avg = None
fnguide = {}
def __init__(self, PROJECT_HOME, stockFileName, fnguideFileName):
self.PROJECT_HOME = PROJECT_HOME
self.stockFileName = stockFileName
self.fnguideFileName = fnguideFileName
self.common = Common()
self.stochastic = Stochastic()
self.bolingerBand = BolingerBand()
self.ichimokuCloud = IchimokuCloud()
return
def readFnguide(self, code):
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"
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()
business_profits, business_profits_ratio, debt_ratio, ROA, ROE, EPS, BPS, DPS, PER, PBR = [], [], [], [], [], [], [], [], [], []
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])
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}
def draw(self, stock):
ymd = list(reversed(stock['ymd']))
open = list(reversed(stock['open']))
close = list(reversed(stock['close']))
high = list(reversed(stock['high']))
low = list(reversed(stock['low']))
volume = list(reversed(stock['volume']))
avg5 = list(reversed(stock['avg5']))
avg20 = list(reversed(stock['avg20']))
avg60 = list(reversed(stock['avg60']))
avg120 = list(reversed(stock['avg120']))
avg240 = list(reversed(stock['avg240']))
stochastic_slow_k = list(reversed(stock['stochastic_slow_k']))
stochastic_slow_d = list(reversed(stock['stochastic_slow_d']))
bolingerband_upper = list(reversed(stock['bolingerband_upper']))
bolingerband_lower = list(reversed(stock['bolingerband_lower']))
ichimokucloud_changeLine = list(reversed(stock['ichimokucloud_changeLine']))
ichimokucloud_baseLine = list(reversed(stock['ichimokucloud_baseLine']))
# general
candle_stick = go.Candlestick(x=ymd, open=open, high=high, low=low, close=close, increasing_line_color='red', decreasing_line_color='blue')
avg5 = go.Scatter(x=ymd, y=avg5, name="avg5", line_color='#000000')
avg20 = go.Scatter(x=ymd, y=avg20, name="avg20", line_color='#f84c43')
avg60 = go.Scatter(x=ymd, y=avg60, name="avg60", line_color='#f89543')
avg120 = go.Scatter(x=ymd, y=avg120, name="avg120", line_color='#0ed604')
avg240 = go.Scatter(x=ymd, y=avg240, name="avg240", line_color='#00FF49')
bolinger_upper = go.Scatter(x=ymd, y=bolingerband_upper, name="upper", line_color='#8B4513')
bolinger_lower = go.Scatter(x=ymd, y=bolingerband_lower, name="lower", line_color='#8B4513')
changeLine = go.Scatter(x=ymd, y=ichimokucloud_changeLine, name="changeLine", line_color='#000000')
baseLine = go.Scatter(x=ymd, y=ichimokucloud_baseLine, name="baseLine", line_color='#FF0000')
candle_data = [candle_stick, avg5, avg20, avg60, avg120, avg240, bolinger_upper, bolinger_lower, changeLine, baseLine]
volume = go.Bar(x=ymd, y=volume, name="volume")
volume_data = [volume]
# stochastic
slow_k = go.Scatter(x=ymd, y=stochastic_slow_k, name="Slow%K", line_color='#8B4513')
slow_d = go.Scatter(x=ymd, y=stochastic_slow_d, name="Slow%D", line_color='#4169E1')
stochastic_data = [slow_k, slow_d]
fig = subplots.make_subplots(rows=3, cols=1, subplot_titles=('차트', '거래량', 'Stochastic'))
for trace in candle_data:
fig.append_trace(trace, 1, 1)
for trace in volume_data:
fig.append_trace(trace, 2, 1)
for trace in stochastic_data:
fig.append_trace(trace, 3, 1)
fig.update_layout(height=1800, xaxis_rangeslider_visible=False)
return fig
def analyzeFinalScore(self, STOCK):
status = ""
if STOCK['volume'][0] > 100000 and STOCK['close'][0] > 1000:
# 거래량이 100만 이상이고, 종가가 1천원 이상인지 체크 (https://happpy-rich.tistory.com/94)
# 정배열 체크
temp_status = self.common.check_RightArrange(STOCK)
if temp_status != "":
status += temp_status
# 20일선 돌파
temp_status = self.common.check_Dolpa_Jiji(STOCK, '20')
if temp_status != "":
status += temp_status
# 60일선 돌파
temp_status = self.common.check_Dolpa_Jiji(STOCK, '60')
if temp_status != "":
status += temp_status
# 120일선 돌파
temp_status = self.common.check_Dolpa_Jiji(STOCK, '120')
if temp_status != "":
status += temp_status
# 240일선 돌파
temp_status = self.common.check_Dolpa_Jiji(STOCK, '240')
if temp_status != "":
status += temp_status
# 20일선 지지 매수가 추천
temp_status = self.common.check_Dolpa_Jiji_20(STOCK)
if temp_status != "":
status += temp_status
# 음봉인데 어제보다 종가가 더 높은 경우
# 이 경우 정배열 상태인지도 함께 체크를 한다.
higher_umbong_status = self.common.checkHigherUmbong(STOCK)
if higher_umbong_status != "":
status += higher_umbong_status
"""
# 단타 #1
temp_status = self.common.check_Danta1(STOCK)
if temp_status != "":
status += temp_status
# 단타 #2
temp_status = self.common.check_Danta2(STOCK)
if temp_status != "":
status += temp_status
all_upper_cross_status = self.common.checkAllUpperCross(STOCK)
if all_upper_cross_status != "":
status += all_upper_cross_status
# 1주일 동안 몇 10% 이상 오른 종목
W1Rise = self.common.check_W1Rise(STOCK, 0.1)
if W1Rise != "":
status += W1Rise
# 1일 동안 몇 10% 이상 내린 종목
W1Fall = self.common.check_D1Fall(STOCK, -0.1)
if W1Fall != "":
status += W1Fall
"""
# GOLDENCROSS#1은 바로 매수하지 않고, 이 시점 이후로 5일선이 20일선을 하방으로 뚫었다가 다시 20일선을 상방으로 뚫는 순간 매수를 시도한다.
# GOLDENCROSS#2은 바로 매수 가능
# GOLDENCROSS#3은 바로 매수 가능
golden_cross_status = self.common.check_golded_cross(STOCK)
if golden_cross_status != "":
status += golden_cross_status
"""
# BUYINGBEARMARKET#1은 바로 매수 가능
# BUYINGBEARMARKET#2은 바로 매수 가능
bearmarket_buying_status = self.common.check_bearmarket_buying(STOCK)
if bearmarket_buying_status != "":
status += bearmarket_buying_status
"""
# STOCHASTIC
stochastic_status = self.common.check_stochastic(STOCK)
if stochastic_status != "":
status += stochastic_status
# YANGBONG
"""
longYangBongAfterUmBong_status = self.common.checkLongYangBongAfterUmBong(STOCK)
# 어제 음봉 이후 장대양봉이었다면,
if longYangBongAfterUmBong_status != "":
status += longYangBongAfterUmBong_status
"""
# Doji
doji_status = self.common.checkDoji(STOCK)
# 하락 추세에서 도지가 나오면 매수
if doji_status != "":
status += doji_status
"""---------------------------------
# Gravestone
gravestone_status = self.common.checkGravestone(STOCK)
# 상승 추세에서 그레이브스톤이 나오면 매도
if gravestone_status != "":
status += gravestone_status
---------------------------------"""
"""
# Dragonfly
dragonfly_status = self.common.checkDragonfly(STOCK)
# 하락 추세에서 드레곤플라이가 나오면 매수
if dragonfly_status != "":
status += dragonfly_status
# Hammer
hammer_status = self.common.checkHammer(STOCK)
# 하락 추세에서 해머가 나오면 매수
if hammer_status != "":
status += hammer_status
"""
"""---------------------------------
# Hangingman
hangingman_status = self.common.checkHangingman(STOCK)
# 상승 추세에서 행잉맨이 나오면 매도
if hangingman_status != "":
status += hangingman_status
---------------------------------"""
"""
# 상승장악형 (Engulfing) - 다음 날도 양봉이라면 매수
engulfing_status = self.common.checkEngulfingHigh(STOCK)
# 하락 추세에서 상승장악형이 나오면 매수
if engulfing_status != "":
status += engulfing_status
"""
"""---------------------------------
# 하락장악형 (Engulfing)
engulfing_status = self.common.checkEngulfingLow(STOCK)
# 상승 추세에서 하락장악형이 나오면 매도
if engulfing_status != "":
status += engulfing_status
---------------------------------"""
"""
# 상승 포아형 (Harami)
harami_status = self.common.checkHaramiHigh(STOCK)
# 하락 추세에서 상승포아형이 나오면 매수
if harami_status != "":
status += harami_status
"""
"""---------------------------------
# 하락 포아형 (Harami)
harami_status = self.common.checkHaramiLow(STOCK)
# 상승 추세에서 하락포아형이 나오면 매도
if harami_status != "":
status += harami_status
---------------------------------"""
"""
# 관통형 (piercing)
piercing_status = self.common.checkPiercing(STOCK)
# 하락 추세에서 관통형이 나오면 매수
if piercing_status != "":
status += piercing_status
"""
"""---------------------------------
# 흑운형 (Dark-cloud)
darkcloud_status = self.common.checkDarkCloud(STOCK)
# 상승 추세에서 흑운형이 나오면 매도
if darkcloud_status != "":
status += darkcloud_status
---------------------------------"""
"""
# 샛별 (Morning start)
morningstar_status = self.common.checkMorningstar(STOCK)
# 하락 추세에서 샛별형이 나오면 매수
if morningstar_status != "":
status += morningstar_status
"""
"""---------------------------------
# 저녁별 (Evening start)
eveningstar_status = self.common.checkEveningstar(STOCK)
# 상승 추세에서 저녁별형이 나오면 매도
if eveningstar_status != "":
status += eveningstar_status
---------------------------------"""
return status
def getPositionalEnergy(self, close):
# 260 (= 52 * 5)일 중 가장 찾은 금액과 가장 높았던 금액 중 현재가의 위치 계산
top = close[0]
bottom = close[0]
for i in range(1, 260):
if i >= len(close):
break
if top < close[i]:
top = close[i]
if bottom > close[i]:
bottom = close[i]
if top-close[0] == 0:
energy1 = 100.0
else:
energy1 = round((close[0]-bottom) / (top-close[0]), 2)
energy2 = round((close[0] / top), 2)
return energy1, energy2
def makeDir(self, type):
if os.path.isdir(self.outPath + "/" + type):
os.rmdir(self.outPath + "/" + type)
os.mkdir(self.outPath + "/" + type)
return
def makeDirectory(self, outPath):
self.outPath = outPath
if os.path.isdir(outPath):
shutil.rmtree(outPath)
os.mkdir(outPath)
self.makeDir("기준선 위 전환선")
self.makeDir("스토케스틱이 10 미만")
self.makeDir("bolingerband 하단 돌파")
self.makeDir("260일 위치 에너지가 10% 미만")
self.makeDir("260일 가격 반토막 이상")
self.makeDir("240일선 아래")
self.makeDir("240일선 돌파")
self.makeDir("20일선 돌파")
self.makeDir("60일선 돌파")
self.makeDir("거래량 5배 이상")
self.makeDir("정배열")
self.makeDir("GoldenCross")
return
def writeFile(self, type, CODE, NAME, stock, state):
fig = self.draw(stock)
title = "%s (%s), %d %s 차트" % (NAME, CODE, stock['close'][0], state)
fig['layout'].update(title=title)
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)
return
# 후보 찾기
def findCandidate(self, outPath):
self.makeDirectory(outPath)
stockTableName = 'stock'
stockAnalysisTableName = 'stock_analysis'
conn = sqlite3.connect(self.stockFileName)
cursor = conn.cursor()
cursor.execute('SELECT distinct code, name FROM ' + stockTableName + ' order by code')
items = cursor.fetchall()
cursor.close()
conn.close()
for idx, item in enumerate(items):
CODE = item[0]
NAME = item[1]
print (idx, CODE, NAME)
conn = sqlite3.connect(self.stockFileName)
cursor = conn.cursor()
sql = 'SELECT ymd, close, open, high, low, volume '
sql += ' FROM ' + stockTableName + ' where CODE=? order by ymd desc limit 260'
cursor.execute(sql, (CODE,))
prices = cursor.fetchall()
ymd_, close, open, high, low, volume = [], [], [], [], [], []
for price in prices:
ymd_.append(price[0])
close.append(price[1])
open.append(price[2])
high.append(price[3])
low.append(price[4])
volume.append(price[5])
sql = 'SELECT ymd, avg5, avg10, avg20, avg60, avg120, avg200, avg240, '
sql += ' bolingerband_upper, bolingerband_lower, bolingerband_middle, '
sql += ' ichimokucloud_changeLine, ichimokucloud_baseLine, ichimokucloud_leadingSpan1, ichimokucloud_leadingSpan2, '
sql += ' stochastic_fast_k, stochastic_slow_k, stochastic_slow_d '
sql += ' FROM ' + stockAnalysisTableName + ' where CODE=? order by ymd desc limit 260'
cursor.execute(sql, (CODE,))
prices = cursor.fetchall()
cursor.close()
conn.close()
ymd = []
avg5, avg10, avg20, avg60, avg120, avg200, avg240 = [], [], [], [], [], [], []
bolingerband_upper, bolingerband_lower, bolingerband_middle = [], [], []
ichimokucloud_changeLine, ichimokucloud_baseLine, ichimokucloud_leadingSpan1, ichimokucloud_leadingSpan2 = [], [], [], []
stochastic_fast_k, stochastic_slow_k, stochastic_slow_d = [], [], []
for price in prices:
ymd.append(price[0])
avg5.append(price[1])
avg10.append(price[2])
avg20.append(price[3])
avg60.append(price[4])
avg120.append(price[5])
avg200.append(price[6])
avg240.append(price[7])
bolingerband_upper.append(price[8])
bolingerband_lower.append(price[8])
bolingerband_middle.append(price[10])
ichimokucloud_changeLine.append(price[11])
ichimokucloud_baseLine.append(price[12])
ichimokucloud_leadingSpan1.append(price[13])
ichimokucloud_leadingSpan2.append(price[14])
stochastic_fast_k.append(price[15])
stochastic_slow_k.append(price[16])
stochastic_slow_d.append(price[17])
stock = {
"ymd":ymd,
"close":close, "open":open, "high":high, "low":low, "volume":volume,
"avg5":avg5, "avg10":avg10, "avg20":avg20, "avg60":avg60, "avg120":avg120, "avg200":avg200, "avg240":avg240,
"bolingerband_upper":bolingerband_upper, "bolingerband_lower":bolingerband_lower, "bolingerband_middle":bolingerband_middle,
"ichimokucloud_changeLine":ichimokucloud_changeLine, "ichimokucloud_baseLine":ichimokucloud_baseLine, "ichimokucloud_leadingSpan1":ichimokucloud_leadingSpan1, "ichimokucloud_leadingSpan2":ichimokucloud_leadingSpan2,
"stochastic_fast_k":stochastic_fast_k, "stochastic_slow_k":stochastic_slow_k, "stochastic_slow_d":stochastic_slow_d
}
stochastic_score = stochastic_slow_k[0]
if bolingerband_upper[0] == bolingerband_lower[0]:
bolingerband_score = 0
else:
bolingerband_score = round(((close[0]-bolingerband_lower[0])/(bolingerband_upper[0]-bolingerband_lower[0])), 2)
# 위치 에너지
positionalEnergy1, positionalEnergy2 = self.getPositionalEnergy(close)
if volume[0] > 100000 and close[0] > 1000:
# 종목 상태 체크 분석
state = self.analyzeFinalScore(stock)
if len(close) > 50:
if (ichimokucloud_changeLine[0] > ichimokucloud_baseLine[0] and
ichimokucloud_changeLine[1] < ichimokucloud_baseLine[1] and
ichimokucloud_changeLine[2] < ichimokucloud_baseLine[2]):
type = "기준선 위 전환선"
self.writeFile(type, CODE, NAME, stock, state)
# 스토케스틱이 10 미만
if len(close) > 5 and stochastic_score is not None and stochastic_score < 10:
type = "스토케스틱이 10 미만"
self.writeFile(type, CODE, NAME, stock, state)
# bolingerband 하단 돌파
if len(close) > 5 and bolingerband_score is not None and bolingerband_score < 0:
type = "bolingerband 하단 돌파"
self.writeFile(type, CODE, NAME, stock, state)
# 260일 위치 에너지가 10% 미만
if len(close) > 5 and positionalEnergy1 is not None and positionalEnergy1 < 0.1:
type = "260일 위치 에너지가 10% 미만"
self.writeFile(type, CODE, NAME, stock, state)
# 260일 가격 반토막 이상
if len(close) > 5 and positionalEnergy2 is not None and positionalEnergy2 < 0.5:
type = "260일 가격 반토막 이상"
self.writeFile(type, CODE, NAME, stock, state)
# 종가가 240일선 아래라면 매수한다.
if close[0] < avg240[0]:
type = "240일선 아래"
self.writeFile(type, CODE, NAME, stock, state)
# 종가가 240일선 돌파
if close[0] > avg240[0] and close[1] < avg240[1]:
type = "240일선 돌파"
self.writeFile(type, CODE, NAME, stock, state)
# 20일선 돌파
temp_status = self.common.check_Dolpa_Jiji(stock, '20')
if temp_status != "":
type = "20일선 돌파"
self.writeFile(type, CODE, NAME, stock, state)
# 60일선 돌파
temp_status = self.common.check_Dolpa_Jiji(stock, '60')
if temp_status != "":
type = "60일선 돌파"
self.writeFile(type, CODE, NAME, stock, state)
golden_cross_status = self.common.check_golded_cross(stock)
if golden_cross_status != "":
type = "GoldenCross"
self.writeFile(type, CODE, NAME, stock, state)
# 거래량 5배 이상
if volume[0] > volume[1]*5:
type = "거래량 5배 이상"
self.writeFile(type, CODE, NAME, stock, state)
right_arrange = self.common.check_RightArrange(stock)
if right_arrange != "":
type = "정배열"
self.writeFile(type, CODE, NAME, stock, state)
return
def get_moving_average(self, stock):
q_5 = MovingAverage(5)
q_10 = MovingAverage(10)
q_20 = MovingAverage(20)
q_60 = MovingAverage(60)
q_120 = MovingAverage(120)
q_200 = MovingAverage(200)
q_240 = MovingAverage(240)
for i in range(len(stock)):
q_5.enqueue(stock[i]['close'])
q_10.enqueue(stock[i]['close'])
q_20.enqueue(stock[i]['close'])
q_60.enqueue(stock[i]['close'])
q_120.enqueue(stock[i]['close'])
q_200.enqueue(stock[i]['close'])
q_240.enqueue(stock[i]['close'])
stock[i]['avg5'] = q_5.avg()
stock[i]['avg10'] = q_10.avg()
stock[i]['avg20'] = q_20.avg()
stock[i]['avg60'] = q_60.avg()
stock[i]['avg120'] = q_120.avg()
stock[i]['avg200'] = q_200.avg()
stock[i]['avg240'] = q_240.avg()
return
def analyze(self):
stockTableName = 'stock'
stockAnalysisTableName = 'stock_analysis'
conn = sqlite3.connect(self.stockFileName)
cursor = conn.cursor()
# 테이블 생성
cursor.execute("CREATE TABLE IF NOT EXISTS " + stockAnalysisTableName + " (CODE text, NAME text, ymd text, avg5 REAL, avg10 REAL, avg20 REAL, avg60 REAL, avg120 REAL, avg200 REAL, avg240 REAL, bolingerband_upper REAL, bolingerband_lower REAL, bolingerband_middle REAL, ichimokucloud_changeLine REAL, ichimokucloud_baseLine REAL, ichimokucloud_leadingSpan1 REAL, ichimokucloud_leadingSpan2 REAL, stochastic_fast_k REAL, stochastic_slow_k REAL, stochastic_slow_d REAL)")
# 키 생성
create_key = "CREATE INDEX IF NOT EXISTS " + stockAnalysisTableName + "_idx on " + stockAnalysisTableName + " (CODE, ymd) "
cursor.execute(create_key)
cursor.execute('SELECT distinct code, name FROM ' + stockTableName + ' order by code')
items = cursor.fetchall()
cursor.close()
conn.close()
for rowid, item in enumerate(items):
conn = sqlite3.connect(self.stockFileName)
cursor = conn.cursor()
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()
for item in items:
stock['PRICE'].append(
{"ymd": item[0],
"close": item[1],
"diff": item[2],
"open": item[3],
"high": item[4],
"low": item[5],
"volume": item[6],
"avg5": -1,
"avg10": -1,
"avg20": -1,
"avg60": -1,
"avg120": -1,
"avg200": -1,
"avg240": -1,
"bolingerband_upper": -1,
"bolingerband_lower": -1,
"bolingerband_middle": -1,
"ichimokucloud_changeLine": -1,
"ichimokucloud_baseLine": -1,
"ichimokucloud_leadingSpan1": -1,
"ichimokucloud_leadingSpan2": -1,
"stochastic_fast_k": -1,
"stochastic_slow_k": -1,
"stochastic_slow_d": -1})
# 이동 평균 계산
stock["PRICE"] = sorted(stock["PRICE"], key=lambda x: x['ymd'])
self.get_moving_average(stock["PRICE"])
self.ichimokuCloud.analyze(stock)
self.stochastic.analyze(stock)
self.bolingerBand.analyze(stock)
for price in stock["PRICE"]:
cursor.execute('SELECT * FROM ' + stockAnalysisTableName + ' WHERE CODE=? and ymd=?', (stock['CODE'], price['ymd'],))
result = cursor.fetchone()
if result == None:
sql = "INSERT INTO " + stockAnalysisTableName + "(CODE, NAME, ymd, avg5, avg10, avg20, avg60, avg120, avg200, avg240, "
sql += " bolingerband_upper, bolingerband_lower, bolingerband_middle, "
sql += " ichimokucloud_changeLine, ichimokucloud_baseLine, ichimokucloud_leadingSpan1, ichimokucloud_leadingSpan2, "
sql += " stochastic_fast_k, stochastic_slow_k, stochastic_slow_d) "
sql += " VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
cursor.execute(sql, (stock["CODE"], stock["NAME"], price['ymd'], price['avg5'], price['avg10'], price['avg20'], price['avg60'], price['avg120'], price['avg200'], price['avg240'],
price['bolingerband_upper'], price['bolingerband_lower'], price['bolingerband_middle'],
price['ichimokucloud_changeLine'], price['ichimokucloud_baseLine'], price['ichimokucloud_leadingSpan1'], price['ichimokucloud_leadingSpan2'],
price['stochastic_fast_k'], price['stochastic_slow_k'], price['stochastic_slow_d'],))
else:
break
conn.commit()
cursor.close()
conn.close()
return
if __name__ == "__main__":
start = time.time()
PROJECT_HOME = os.path.join(os.path.dirname(os.path.join(os.path.dirname(os.path.join(os.path.dirname(__file__))))))
stockFileName = PROJECT_HOME + '/resources/stock.db'
fnguideFileName = PROJECT_HOME + '/resources/fnguide.db'
analyzer = AnalyzerSqlite(PROJECT_HOME, stockFileName, fnguideFileName)
#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.findCandidate(outPath)
print("time : %6.2f" % (time.time() - start))
print("done...")

View File

@@ -12,18 +12,17 @@ class BolingerBand:
self.common = Common()
return
def apply(self, df, n=10, m=6, t=6):
def apply(self, df, n=20, t=2):
# 입력받은 값이 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) # 하단 볼리저 밴드
max20 = df["close"].rolling(window=n).mean()
stddev = df["close"].rolling(window=n).std()
upper = max20 + (stddev * t) # 상단 볼리저 밴드
lower = max20 - (stddev * t) # 하단 볼리저 밴드
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
@@ -34,21 +33,8 @@ class BolingerBand:
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]
stock['PRICE'][i]['bolingerband_upper'] = df.upper.values[i]
stock['PRICE'][i]['bolingerband_middle'] = df.middle.values[i]
stock['PRICE'][i]['bolingerband_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
return

View File

@@ -0,0 +1,560 @@
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 getBolingerBandScore(self, stock, i):
return 0
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
# YANGBONG
# 어제 음봉 이후 장대양봉이었다면, 매수
def checkLongYangBongAfterUmBong(self, stock, i):
if i > 0:
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 "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:
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_Dolpa(self, stock, i, avg1, avg2):
upper_index = 0
if len(stock) > 2:
if stock[i-1]["avg"+avg1] < stock[i-1]["avg"+avg2] and stock[i]["avg"+avg1] > stock[i]["avg"+avg2]:
return avg1+"_"+avg2+"_"
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 checkHigherUmbong(self, stock, i):
# 음봉인데 어제보다 종가가 더 높은 경우
# 이 경우 정배열 상태인지도 함께 체크를 한다.
if len(stock) > 3:
# 어제는 거래량이 터진 양봉이다.
if stock[i-1]['open'] < stock[i-1]['close'] and 5*stock[i-2]['volume'] < stock[i-1]['volume']:
# 오늘은 음봉인데, 오늘 종가는 어제 시가보다는 높다
if stock[i]['close'] < stock[i]['open'] and stock[i-1]['open'] < stock[i]['close']:
return "HIGHERUMBONG_"
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

@@ -48,292 +48,212 @@ class Common:
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 getBolingerBandScore(self, stock, i):
return 0
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
# YANGBONG
# 어제 음봉 이후 장대양봉이었다면, 매수
def checkLongYangBongAfterUmBong(self, stock, i):
if i > 0:
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']: # 어제 거래량 보다 두배 이상일 때
def checkLongYangBongAfterUmBong(self, stock):
if len(stock['close']) > 2:
if stock['close'][1] < stock['open'][1]: # 어제가 음봉인지 체크
if stock['open'][0] < stock['close'][0] and stock['close'][0] == stock['high'][0]: # 오늘 장대양봉인지 체크
if stock['volume'][1]*2 < stock['volume'][0]: # 어제 거래량 보다 두배 이상일 때
return "UMYANG_"
return ""
def checkDoji(self, stock, i):
def checkDoji(self, stock):
# 하락 추세이고, 그저께, 어제 음봉이고, 오늘 도지인지 체크한다
if i > 2:
if len(stock['close']) > 2:
# 하락 추세이고
if stock[i - 1]['close'] < stock[i - 2]['close']:
if stock['close'][1] < stock['close'][2]:
# 그저께와 어제가 음봉인지 체크
if stock[i-2]['close'] < stock[i-2]['open'] and stock[i-1]['close'] < stock[i-1]['open']:
if stock['close'][2] < stock['open'][2] and stock['close'][1] < stock['open'][1]:
# 도지 체크
if stock[i]['open'] == stock[i]['close'] and stock[i]['low'] < stock[i]['close'] < stock[i]['high']:
if stock['open'][0] == stock['close'][0] and stock['low'][0] < stock['close'][0] < stock['high'][0]:
return "DOJI_"
return ""
def checkGravestone(self, stock, i):
def checkGravestone(self, stock):
# 상승 추세이고, 어제 양봉이고, 오늘 그레이브스톤인지 체크한다
if i > 2:
if len(stock['close']) > 2:
# 상승 추세이고
if stock[i-2]['close'] < stock[i - 1]['close']:
if stock['close'][2] < stock['close'][1]:
# 어제 양봉인지 체크
if stock[i-1]['open'] < stock[i-1]['close']:
if stock['open'][1] < stock['close'][1]:
# 오늘 그레이브스톤인지 체크한다
if stock[i]['open'] == stock[i]['close'] == stock[i]['low'] and stock[i]['low'] < stock[i]['high']:
if stock['open'][0] == stock['close'][0] == stock['low'][0] and stock['low'][0] < stock['high'][0]:
return "GRAVESTONE_"
return ""
# 하락 추세에서 드레곤플라이가 나오면 매수
def checkDragonfly(self, stock, i):
def checkDragonfly(self, stock):
# 하락 추세이고, 그저께, 어제 음봉이고, 오늘 드레곤플라이인지 체크한다
if i > 1:
if len(stock['close']) > 2:
# 하락 추세이고
if stock[i - 1]['close'] < stock[i - 2]['close']:
if stock['close'][1] < stock['close'][1]:
# 그저께와 어제가 음봉인지 체크
if stock[i - 2]['close'] < stock[i - 2]['open'] and stock[i - 1]['close'] < stock[i - 1]['open']:
if stock['close'][2] < stock['open'][2] and stock['close'][1] < stock['open'][1]:
# 오늘 드레곤플라이인지 체크한다
if stock[i]['open'] == stock[i]['close'] == stock[i]['high'] and stock[i]['low'] < stock[i]['high']:
if stock['open'][0] == stock['close'][0] == stock['high'][0] and stock['low'][0] < stock['high'][0]:
return "DRAGONEFLY_"
return ""
def checkHammer(self, stock, i):
def checkHammer(self, stock):
# 하락 추세이고, 그저께, 어제 음봉이고, 오늘 해머인지 체크한다
if i > 1:
if len(stock['close']) > 2:
# 하락 추세이고
if stock[i - 1]['close'] < stock[i - 2]['close']:
if stock['close'][1] < stock['close'][1]:
# 그저께와 어제가 음봉인지 체크
if stock[i - 2]['close'] < stock[i - 2]['open'] and stock[i - 1]['close'] < stock[i - 1]['open']:
if stock['close'][2] < stock['open'][2] and stock[1]['close'] < stock[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['open'][0] < stock['close'][0]:
if (stock['close'][0] - stock['open'][0]) * 2 < stock['open'][0] - stock['low'][0]:
# 윗꼬리가 몸통보다 짧아야 한다.
if stock[i]['high'] - stock[i]['close'] < stock[i]['close'] - stock[i]['open']:
if stock['high'][0] - stock['close'][0] < stock['close'][0] - stock['open'][0]:
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['close'][0] < stock['open'][0]:
if (stock['open'][0] - stock['close'][0]) * 2 < stock['close'][0] - stock['low'][0]:
# 윗꼬리가 몸통보다 짧아야 한다.
if stock[i]['high'] - stock[i]['open'] < stock[i]['open'] - stock[i]['close']:
if stock['high'][0] - stock['open'][0] < stock['open'][0] - stock['close'][0]:
return "HAMMER_"
return ""
def checkHangingman(self, stock, i):
def checkHangingman(self, stock):
# 상승 추세이고, 어제 양봉이고, 오늘 행잉맨인지 체크한다
if i > 2:
if len(stock['close']) > 2:
# 상승 추세이고
if stock[i-2]['close'] < stock[i - 1]['close']:
if stock['close'][2] < stock['close'][1]:
# 어제 양봉인지 체크
if stock[i-1]['open'] < stock[i-1]['close']:
if stock['open'][1] < stock['close'][1]:
# 오늘 해머인지 체크한다
if stock[i]['open'] < stock[i]['close']:
if (stock[i]['close'] - stock[i]['open']) * 2 < stock[i]['open'] - stock[i]['low']:
if stock['open'][0] < stock['close'][0]:
if (stock['close'][0] - stock['open'][0]) * 2 < stock['open'][0] - stock['low'][0]:
# 윗꼬리가 몸통보다 짧아야 한다.
if stock[i]['high'] - stock[i]['close'] < stock[i]['close'] - stock[i]['open']:
if stock['high'][0] - stock['close'][0] < stock['close'][0] - stock['open'][0]:
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['close'][0] < stock['open'][0]:
if (stock['open'][0] - stock['close'][0]) * 2 < stock['close'][0] - stock['low'][0]:
# 윗꼬리가 몸통보다 짧아야 한다.
if stock[i]['high'] - stock[i]['open'] < stock[i]['open'] - stock[i]['close']:
if stock['high'][0] - stock['open'][0] < stock['open'][0] - stock['close'][0]:
return "HANGINGMAN_"
return ""
def checkEngulfingHigh(self, stock, i):
def checkEngulfingHigh(self, stock):
# 하락 추세에서 상승 장악형인지 체크
if i > 2:
if len(stock['close']) > 2:
# 하락 추세이고
if stock[i - 1]['close'] < stock[i - 2]['close']:
if stock['close'][1] < stock['close'][2]:
# 그저께와 어제가 음봉인지 체크
if stock[i - 2]['close'] < stock[i - 2]['open'] and stock[i - 1]['close'] < stock[i - 1]['open']:
if stock['close'][2] < stock['open'][2] and stock['close'][1] < stock['open'][1]:
# 오늘 상승장악형인지 체크
if stock[i]['open'] < stock[i]['close']:
if stock[i-1]['open'] < stock[i]['close'] and stock[i]['open'] < stock[i-1]['close']:
if stock['open'][0] < stock['close'][0]:
if stock['open'][1] < stock['close'][0] and stock['open'][0] < stock['close'][1]:
return "ENHIGH_"
return ""
def checkEngulfingLow(self, stock, i):
def checkEngulfingLow(self, stock):
# 상승 추세에서 하락 장악형인지 체크
if i > 2:
if len(stock['close']) > 2:
# 상승 추세이고
if stock[i - 2]['close'] < stock[i - 1]['close']:
if stock['close'][2] < stock['close'][1]:
# 어제 양봉인지 체크
if stock[i - 1]['open'] < stock[i - 1]['close']:
if stock['open'][1] < stock['close'][1]:
# 오늘 하락장악형인지 체크
if stock[i]['close'] < stock[i]['open']:
if stock[i-1]['close'] < stock[i]['open'] and stock[i]['close'] < stock[i-1]['open']:
if stock['close'][0] < stock['open'][0]:
if stock['close'][1] < stock['open'][0] and stock['close'][0] < stock['open'][1]:
return "ENLOW_"
return ""
def checkHaramiHigh(self, stock, i):
def checkHaramiHigh(self, stock):
# # 하락 추세에서 상승포아형인지 체크
if i > 2:
if len(stock['close']) > 2:
# 하락 추세이고
if stock[i - 1]['close'] < stock[i - 2]['close']:
if stock['close'][1] < stock['close'][2]:
# 그저께와 어제가 음봉인지 체크
if stock[i - 2]['close'] < stock[i - 2]['open'] and stock[i - 1]['close'] < stock[i - 1]['open']:
if stock['close'][2] < stock['open'][2] and stock['close'][1] < stock['open'][1]:
# 오늘 상승포아형인지 체크
if stock[i]['open'] < stock[i]['close']:
if stock[i-1]['close'] < stock[i]['low'] and stock[i]['high'] < stock[i-1]['open']:
if stock['open'][0] < stock['close'][0]:
if stock['close'][1] < stock['low'][0] and stock['high'][0] < stock['open'][1]:
return "HAHIGH_"
return ""
def checkHaramiLow(self, stock, i):
def checkHaramiLow(self, stock):
# 상승 추세에서 하락 포아형인지 체크
if i > 2:
if len(stock['close']) > 2:
# 상승 추세이고
if stock[i - 2]['close'] < stock[i - 1]['close']:
if stock['close'][2] < stock['close'][1]:
# 어제 양봉인지 체크
if stock[i - 1]['open'] < stock[i - 1]['close']:
if stock['open'][1] < stock['close'][1]:
# 오늘 하락포아형인지 체크
if stock[i]['close'] < stock[i]['open']:
if stock[i-1]['open'] < stock[i]['low'] and stock[i]['high'] < stock[i-1]['close']:
if stock['close'][0] < stock['open'][0]:
if stock['open'][1] < stock['low'][0] and stock['high'][0] < stock['close'][1]:
return "HALOW_"
return ""
def checkPiercing(self, stock, i):
def checkPiercing(self, stock):
# 하락 추세에서 관통형인지 체크
if i > 2:
if len(stock['close']) > 2:
# 하락 추세이고
if stock[i - 1]['close'] < stock[i - 2]['close']:
if stock['close'][1] < stock['close'][2]:
# 그저께와 어제가 음봉인지 체크
if stock[i - 2]['close'] < stock[i - 2]['open'] and stock[i - 1]['close'] < stock[i - 1]['open']:
if stock['close'][2] < stock['open'][2] and stock['close'][1] < stock['open'][1]:
# 오늘 관통형인지 체크
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']:
if stock['open'][0] < stock['close'][0]:
if stock['open'][0] < stock['low'][1] and (stock['close'][1] + stock['open'][1])/2 < stock['close'][0] < stock['close'][1]:
return "PIERCING_"
return ""
def checkDarkCloud(self, stock, i):
def checkDarkCloud(self, stock):
# 상승 추세에서 흑운형인지 체크
if i > 2:
if len(stock['close']) > 2:
# 상승 추세이고
if stock[i - 2]['close'] < stock[i - 1]['close']:
if stock['close'][2] < stock['close'][1]:
# 어제 양봉인지 체크
if stock[i - 1]['open'] < stock[i - 1]['close']:
if stock['open'][1] < stock['close'][1]:
# 오늘 흑운형인지 체크
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:
if stock['close'][0] < stock['open'][0]:
if stock['high'][1] < stock['open'][0] and stock['open'][1] < stock['close'][0] < (stock['open'][1] + stock['close'][1])/2:
return "DARKCLOUD_"
return ""
def checkMorningstar(self, stock, i):
def checkMorningstar(self, stock):
# 하락 추세에서 샛별인지 체크
if i > 3:
if len(stock['close']) > 2:
# 하락 추세이고
if stock[i-1]['close'] < stock[i-2]['close']:
if stock['close'][1] < stock['close'][2]:
# 그저께와 어제가 음봉인지 체크
if stock[i - 2]['close'] < stock[i - 2]['open'] and stock[i - 1]['close'] < stock[i - 1]['open']:
if stock['close'][2] < stock['open'][2] and stock['close'][1] < stock['open'][1]:
# 오늘 샛별인지 체크
# 어제 갭 체크
if stock[i-1]['open'] < stock[i - 2]['close'] and stock[i-1]['close'] < stock[i - 2]['close']:
if stock['open'][1] < stock['close'][2] and stock['close'][1] < stock['close'][2]:
# 오늘 시가가 어제 종가보다 높으며 양봉
if stock[i-1]['close'] < stock[i]['open'] < stock[i]['close']:
if stock['close'][1] < stock['open'][0] < stock['close'][0]:
return "MORNINGSTAR_"
return ""
def checkEveningstar(self, stock, i):
def checkEveningstar(self, stock):
# 상승 추세에서 저녁별형인지 체크
if i > 3:
if len(stock['close']) > 2:
# 상승 추세이고
if stock[i-2]['close'] < stock[i-1]['close']:
if stock['close'][2] < stock['close'][1]:
# 어제 양봉인지 체크
if stock[i-1]['open'] < stock[i-1]['close']:
if stock['open'][1] < stock['close'][1]:
# 오늘 저녁별형인지 체크
# 어제 갭 체크
if stock[i-2]['close'] < stock[i-1]['open'] and stock[i-2]['close'] < stock[i-1]['close']:
if stock['close'][2] < stock['open'][1] and stock['close'][2] < stock['close'][1]:
# 오늘 시가가 어제 종가보다 낮으며 음봉
if stock[i]['close'] < stock[i-1]['open'] < stock[i-1]['close']:
if stock['close'][0] < stock['open'][1] < stock['close'][1]:
return "EVENINGSTAR_"
return ""
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']:
def checkAllUpperCross(self, stock):
if len(stock['close']) > 10:
if stock['avg5'][0] < stock['close'][0] and stock['avg20'][0] < stock['close'][0] and stock['avg60'][0] < stock['close'][0] and stock['avg120'][0] < stock['close'][0]:
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']:
if stock['close'][j] < stock['avg5'][j] and stock['close'][j] < stock['avg20'][j] and stock['close'][j] < stock['avg60'][j] and stock['close'][j] < stock['avg120'][j]:
return "ALLUPPER_"
return ""
def check_golded_cross(self, stock, i):
if i > 1:
def check_golded_cross(self, stock):
if len(stock['close']) > 1:
# 60 -> 120
# 오늘 지수는 120 < 60 < 20 < 5
# 어제 지수는 60 < 120 이었다.
@@ -341,40 +261,40 @@ class Common:
# 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']):
if stock['avg120'][0] < stock['avg60'][0] < stock['avg20'][0] < stock['avg5'][0]:
if stock['avg120'][1] > stock['avg60'][1]:
if (stock['avg60'][1] < stock['avg60'][0] and stock['avg20'][1] < stock['avg20'][0] and stock['avg5'][1] < stock['avg5'][0]):
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']):
if stock['avg60'][0] < stock['avg120'][0] < stock['avg20'][0] < stock['avg5'][0]:
if stock['avg60'][1] < stock['avg20'][1] < stock['avg120'][0] < stock['avg5'][0]:
if (stock['avg60'][1] < stock['avg60'][0] and stock['avg20'][1] < stock['avg20'][0] and stock['avg5'][1] < stock['avg5'][0]):
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']):
if stock['avg60'][0] < stock['avg120'][0] < stock['avg20'][0] < stock['avg5'][0]:
if stock['avg60'][1] < stock['avg20'][1] < stock['avg120'][0] < stock['avg5'][0]:
if (stock['avg60'][1] < stock['avg60'][0] and stock['avg20'][1] < stock['avg20'][0] and stock['avg5'][1] < stock['avg5'][0]):
return "GOLDEN#3_"
return ""
def check_bearmarket_buying(self, stock, stochastic, i):
if i > 1:
def check_bearmarket_buying(self, stock):
if len(stock['close']) > 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'])):
if (stock['avg5'][1] < stock['avg20'][1] < stock['avg120'][1] < stock['avg60'][0]) and (stock['avg20'][0] < stock['avg120'][1] < stock['avg60'][0]):
if stock['avg120'][0] < stock['avg120'][1] and stock['avg60'][0] < stock['avg60'][1] and stock['avg20'][0] < stock['avg20'][1]:
if stock['close'][1] <= stock['close'][0] and stock['avg5'][0] <= stock['close'][0]:
if (stock['stochastic_slow_k'][0] < 30 and (stock['stochastic_slow_k'][1] < stock['stochastic_slow_d'][1] and stock['stochastic_slow_d'][0] < stock['stochastic_slow_k'][0])):
return "BEARMARKET#1_"
# 5일선 상승 시점 확인 (원풍물산 2020년 3월 24일, NHN한국사이버결제 2018년 11월 2일)
@@ -382,24 +302,24 @@ class Common:
# 어제와 오늘 모두 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'])):
if (stock['avg5'][1] < stock['avg20'][1] < stock['avg60'][1] < stock['avg120'][0]) and (stock['avg20'][0] < stock['avg60'][1] < stock['avg120'][0]):
if stock['avg120'][0] < stock['avg120'][1] and stock['avg60'][0] < stock['avg60'][1] and stock['avg20'][0] < stock['avg20'][1]:
if stock['close'][1] <= stock['close'][0] and stock['avg5'][0] <= stock['close'][0]:
if (stock['stochastic_slow_k'][0] < 30 and (stock['stochastic_slow_k'][1] < stock['stochastic_slow_d'][1] and stock['stochastic_slow_d'][0] < stock['stochastic_slow_k'][0])):
return "BEARMARKET#2_"
return ""
def check_stochastic(self, stock, stochastic, i):
if i > 2:
def check_stochastic(self, stock):
if len(stock['close']) > 60:
# 스토케스틱이 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']:
if stock['stochastic_slow_k'][0] < 15:
if stock['stochastic_slow_k'][1] < stock['stochastic_slow_k'][0] and stock['stochastic_slow_d'][0] < stock['stochastic_slow_k'][0]:
return "STOCHASTIC_"
return ""
def check_stochastic_buying(self, stock, stochastic, ichimoku, i):
if i > 3:
if len(stock['close']) > 60:
# 삼성전자 2020년 11월 4일
# 어제는 slow_K가 Slow_d 아래였지만, 오늘은 slow_K가 Slow_d 보다 높다.
# 에제의 slow_k는 20보다 작고, 오늘의 slow_K는 30보다 작다
@@ -422,29 +342,29 @@ class Common:
def check_Dolpa(self, stock, i, avg1, avg2):
upper_index = 0
if len(stock) > 2:
if len(stock['close']) > 2:
if stock[i-1]["avg"+avg1] < stock[i-1]["avg"+avg2] and stock[i]["avg"+avg1] > stock[i]["avg"+avg2]:
return avg1+"_"+avg2+"_"
return ""
def check_Dolpa_Jiji(self, stock, i, day='20'):
def check_Dolpa_Jiji(self, stock, day='20'):
upper_index = 0
if len(stock) > 5:
if len(stock['close']) > 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']:
if stock['open'][idx] < stock["avg"+day][idx] < stock['close'][idx] and stock['high'][idx] - 100 <= stock['close'][idx]:
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['close'][upper_index] <= stock['open'][cidx] and stock['open'][cidx] < stock['close'][cidx]:
# 해당 기준일 선은 상승이어야 한다.
if stock[-upper_index]['avg'+day] < stock[-cidx]['avg'+day]:
if stock['avg'+day][upper_index] < stock['avg'+day][cidx]:
return day + "_"
return ""
def check_Dolpa_Jiji_20(self, stock, i):
def check_Dolpa_Jiji_20(self, stock):
"""
top: 이전 5일선이 20일선 위에 있을 때 최고가
top일 체크 사항 (20일 < 5일선)
@@ -452,28 +372,28 @@ class Common:
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']:
if len(stock['close']) > 61:
if stock['avg20'][0] < stock['close'][0] and stock['avg20'][0] < stock['open'][0]:
if stock['avg5'][0] < stock['avg20'][0]:
index1 = -1
for j in range(1, 61):
if stock[i-j]['avg20'] < stock[i-j]['avg5']:
if stock['avg20'][j] < stock['avg5'][j]:
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']
if stock['open'][j] < stock['close'][j]:
if top < stock['close'][j]:
top = stock['close'][j]
else:
if top < stock[i - j]['open']:
top = stock[i - j]['open']
if stock[i-j]['avg5'] < stock[i-j]['avg20']:
if top < stock['open'][j]:
top = stock['open'][j]
if stock['avg5'][j] < stock['avg20'][j]:
break
return "5-20_"
return ""
def check_Danta1(self, stock, i):
def check_Danta1(self, stock):
"""
어제 상한가 혹은 상승양봉이 나온다.
오늘 상승 출발을 해야 하며 상승 음봉이 나온다
@@ -483,78 +403,79 @@ class Common:
만약 다음날 시작초가가 오늘 종가보다 높게 상승으로 출발한다면 매수를 한다.
손절가는 오늘 최저가이다.
"""
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']:
if stock['open'][1] < stock['close'][1] == stock['high'][1]:
if stock['close'][1] < stock['close'][0] < stock['open'][0] < stock['high'][0]:
return "danta1_"
return ""
def check_Danta2(self, stock, i):
def check_Danta2(self, stock):
"""
쐐기, 수렴, 깃대 패턴 확인
# 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"]
price_10 = round(stock["close"][0] / 10)
if stock["open"][0] < stock["close"][0]:
top = stock["close"][0]
bottom = stock["open"][0]
else:
top = stock[-i]["open"]
bottom = stock[-i]["close"]
top = stock["open"][0]
bottom = stock["close"][0]
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"]
if stock["open"][i] < stock["close"][i]:
if top < stock["close"][i]:
top = stock["close"][i]
if stock["open"][i] < bottom:
bottom = stock["open"][i]
else:
if top < stock[-i]["open"]:
top = stock[-i]["open"]
if stock[-i]["close"] < bottom:
bottom = stock[-i]["close"]
if top < stock["open"][i]:
top = stock["open"][i]
if stock["close"][i] < bottom:
bottom = stock["close"][i]
if top - bottom < price_10:
return "danta2_"
return ""
def check_RightArrange(self, stock, i):
def check_RightArrange(self, stock):
"""
어제는 정배열이 아니었는데, 오늘은 정배열인 경우
"""
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"]):
if len(stock['close']) > 2:
if (not (stock["avg120"][1] < stock["avg60"][1] < stock["avg20"][1] < stock["avg5"][1] < stock["close"][1]) and
stock["avg120"][0] < stock["avg60"][0] < stock["avg20"][0] < stock["avg5"][0] < stock["close"][0]):
return "arrange_"
return ""
def checkHigherUmbong(self, stock, i):
def checkHigherUmbong(self, stock):
# 음봉인데 어제보다 종가가 더 높은 경우
# 이 경우 정배열 상태인지도 함께 체크를 한다.
if len(stock) > 3:
if len(stock['close']) > 3:
# 어제는 거래량이 터진 양봉이다.
if stock[i-1]['open'] < stock[i-1]['close'] and 5*stock[i-2]['volume'] < stock[i-1]['volume']:
if stock['open'][1] < stock['close'][1] and 5*stock['volume'][2] < stock['volume'][1]:
# 오늘은 음봉인데, 오늘 종가는 어제 시가보다는 높다
if stock[i]['close'] < stock[i]['open'] and stock[i-1]['open'] < stock[i]['close']:
if stock['close'][0] < stock['open'][0] and stock['open'][1] < stock['close'][0]:
return "HIGHERUMBONG_"
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)
def check_W1Rise(self, stock, limit):
if len(stock['close']) > 5:
rate = round((stock["close"][0] - stock["close"][4]) / stock["close"][4],2)
if rate >= limit:
return "1w("+str(rate)+")_"
return ""
def check_D1Fall(self, stock, i, limit):
if len(stock) > 2:
def check_D1Fall(self, stock, limit):
if len(stock['close']) > 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)
rate = round((stock["close"][0] - stock["close"][1]) / stock["close"][1], 2)
if rate <= limit:
return "1d("+str(rate)+")_"
return ""

View File

@@ -93,34 +93,24 @@ class IchimokuCloud:
df = self.apply(df)
diff = len(df.changeLine) - len(stock['PRICE'])
lastDay = stock['PRICE'][len(stock['PRICE']) - 1]['DATE']
tmpLastDay = datetime.datetime.strptime(lastDay, "%Y-%m-%d")
"""
lastDay = stock['PRICE'][len(stock['PRICE']) - 1]['ymd']
tmpLastDay = datetime.datetime.strptime(lastDay, "%Y.%m.%d")
for i in range(diff):
nextDay = tmpLastDay + datetime.timedelta(days=(i + 1))
stock['PRICE'].append(
{"DATE": nextDay.strftime("%Y-%m-%d"), "close": 0, "diff": 0, "open": 0, "high": 0, "low": 0, "volume": 0,
{"ymd": nextDay.strftime("%Y-%m-%d"), "close": 0, "diff": 0, "open": 0, "high": 0, "low": 0, "volume": 0,
"avg3": 0, "avg5": 0, "avg7": 0, "avg10": 0, "avg20": 0, "avg30": 0, "avg60": 0, "avg90": 0, "avg100": 0,
"avg120": 0, "avg150": 0, "avg180": 0, "avg200": 0, "avg240": 0})
"""
for i in range(len(df.changeLine)):
stock['PRICE'][i]['ichimoku_buy'] = 0
stock['PRICE'][i]['changeLine'] = df.changeLine.values[i]
stock['PRICE'][i]['baseLine'] = df.baseLine.values[i]
stock['PRICE'][i]['leadingSpan1'] = df.leadingSpan1.values[i]
stock['PRICE'][i]['leadingSpan2'] = df.leadingSpan2.values[i]
for i in range(len(df.changeLine)-diff):
stock['PRICE'][i]['ichimokucloud_changeLine'] = df.changeLine.values[i]
stock['PRICE'][i]['ichimokucloud_baseLine'] = df.baseLine.values[i]
stock['PRICE'][i]['ichimokucloud_leadingSpan1'] = df.leadingSpan1.values[i]
stock['PRICE'][i]['ichimokucloud_leadingSpan2'] = df.leadingSpan2.values[i]
for i in range(len(df.changeLine)):
stock['PRICE'][i]['ichimoku_buy'] = self.common.getIchimokuCloudScore(stock['PRICE'], i)
results = []
for day in stock['PRICE']:
results.append({'DATE': day['DATE'],
'changeLine': day['changeLine'],
'baseLine': day['baseLine'],
'leadingSpan1': day['leadingSpan1'],
'leadingSpan2': day['leadingSpan2'],
'ichimoku_buy': day['ichimoku_buy']})
return results
return
if __name__ == "__main__":

View File

@@ -15,7 +15,9 @@ class Stochastic:
# 일자(n,m,t)에 따른 Stochastic(KDJ)의 값을 구하기 위해 함수형태로 만듬
# n=15 (%k), m=5 (%d), t=3
def apply(self, df, n=5, m=3, t=3):
# n=5 (%k), m=3 (%d), t=3
# n=14 (%k), m=3 (%d), t=3
def apply(self, df, n=14, m=3, t=3):
# 입력받은 값이 dataframe이라는 것을 정의해줌
df = pd.DataFrame(df)
@@ -130,31 +132,16 @@ class Stochastic:
df = self.apply(df)
for i in range(len(df.fast_k)):
stock['PRICE'][i]['stochastic_buy'] = 0
if "fast_k" not in stock['PRICE'][i]:
stock['PRICE'][i]['fast_k'] = -1
stock['PRICE'][i]['slow_k'] = -1
stock['PRICE'][i]['slow_d'] = -1
if "stochastic_fast_k" not in stock['PRICE'][i]:
stock['PRICE'][i]['stochastic_fast_k'] = -1
stock['PRICE'][i]['stochastic_slow_k'] = -1
stock['PRICE'][i]['stochastic_slow_d'] = -1
stock['PRICE'][i]['fast_k'] = df.fast_k.values[i]
stock['PRICE'][i]['slow_k'] = df.slow_k.values[i]
stock['PRICE'][i]['slow_d'] = df.slow_d.values[i]
stock['PRICE'][i]['stochastic_fast_k'] = df.fast_k.values[i]
stock['PRICE'][i]['stochastic_slow_k'] = df.slow_k.values[i]
stock['PRICE'][i]['stochastic_slow_d'] = df.slow_d.values[i]
# 0: 중립, 1: 매수, -1: 매도
stock['PRICE'][i]['stochastic_buy'] = 0
if i > 0:
if ('slow_k' in stock['PRICE'][i-1] and 'slow_k' in stock['PRICE'][i]):
stock['PRICE'][i]['stochastic_buy'] = self.common.getStochasticScore(stock['PRICE'], i)
results = []
for day in stock['PRICE']:
results.append({'DATE': day['DATE'],
'fast_k': day['fast_k'],
'slow_k': day['slow_k'],
'slow_d': day['slow_d'],
'stochastic_buy': day['stochastic_buy']})
return results
return
if __name__ == "__main__":
stochastic = Stochastic()

View File

@@ -0,0 +1,71 @@
import os
import shutil
import datetime
import time
from stockpredictor.crawler.sQLite.FnGuideCrawler import FnGuideCrawler
from stockpredictor.crawler.sQLite.MetaCrawler import MetaCrawler
from stockpredictor.crawler.sQLite.StockCrawler import StockCrawler
from stockpredictor.analysis.AnalyzerSqlite import AnalyzerSqlite
today = datetime.datetime.now().strftime("%Y-%m-%d")
# DB Browser for SQLite: http://hleecaster.com/python-sqlite3/
PROJECT_HOME = os.path.join(os.path.dirname(os.path.join(os.path.dirname(os.path.join(os.path.dirname(os.path.join(os.path.dirname(__file__))))))))
start = time.time()
# 재무제표는 3개월마다 다운로드를 한다.
fnGuideCrawler = FnGuideCrawler()
inFnguideFileName = PROJECT_HOME + '/resources/fnguide.db'
print("[KOSPI 상장기업 재무제표 다운로드]")
fnGuideCrawler.crawl_fnguide(inFnguideFileName)
metaCrawler = MetaCrawler()
print("\n[증시자금동향 (신용잔고, 펀드자금 잔고)]")
inFileName = PROJECT_HOME + '/resources/meta_3.db'
metaCrawler.crawl_money_trend(inFileName)
print("\n[국내 시장금리]")
inFileName = PROJECT_HOME + '/resources/meta_4.db'
metaCrawler.crawl_interest_rates(inFileName)
print("\n[투자자별 매매동향(Trading_Trend)]")
inFileName = PROJECT_HOME + '/resources/meta_2.db'
metaCrawler.crawl_trading_trend(inFileName)
print("\n[환율 (USD, JPY, EUR, CNY)]")
inFileName = PROJECT_HOME + '/resources/meta_1.db'
metaCrawler.crawl_exchange(inFileName)
print("\n[원유 (WTI), 국제금, COPPER, NATURALGAS, CORN, SOYBEAN]")
inFileName = PROJECT_HOME + '/resources/meta_5.db'
metaCrawler.crawl_meterials(inFileName)
print("\n[종목 다운로드]")
stockCrawler = StockCrawler()
inFileName = PROJECT_HOME + '/resources/stock.db'
stockCrawler.crawl_etf_stocks(inFileName)
stockCrawler.crawl_stocks(inFileName)
print("\n[종목 분석]")
# S: 분석까지 진행
inFileName = PROJECT_HOME + '/resources/stock.db'
analyzerSqlite = AnalyzerSqlite(PROJECT_HOME, inFileName, inFnguideFileName)
analyzerSqlite.analyze()
print("\n[종목 결정]")
day = datetime.datetime.today().strftime("%Y%m%d")
outPath = PROJECT_HOME + "/resources/analysis/" + day
if os.path.isdir(outPath):
shutil.rmtree(outPath)
os.mkdir(outPath)
print("print to Html...")
analyzerSqlite.findCandidate(outPath)
# E: 분석까지 진행
print("time : %6.2f", (time.time() - start))
print ("done...")

View File

@@ -0,0 +1,220 @@
from bs4 import BeautifulSoup
from pandas import DataFrame, Series
import requests as re
import pandas as pd
import os
import json
import sqlite3
import requests
class FnGuideCrawler:
header = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'}
def getStockInfo(self):
code_df = pd.read_html('http://kind.krx.co.kr/corpgeneral/corpList.do?method=download&searchType=13', header=0)[0]
#code_df = pd.read_html(requests.get('http://kind.krx.co.kr/corpgeneral/corpList.do?method=download&searchType=13', headers=self.header).text)
# 종목코드가 6자리이기 때문에 6자리를 맞춰주기 위해 설정해줌
code_df.종목코드 = code_df.종목코드.map('{:06d}'.format)
# 우리가 필요한 것은 회사명과 종목코드이기 때문에 필요없는 column들은 제외해준다.
code_df = code_df[['회사명', '종목코드']]
# 한글로된 컬럼명을 영어로 바꿔준다.
code_df = code_df.rename(columns={'회사명': 'name', '종목코드': 'code'})
###print (code_df.head())
return code_df
# FnGuide에서 크롤링한 KOSPI 상장기업의 재무제표
# http://blog.naver.com/PostView.nhn?blogId=koko8624&logNo=221294884955&parentCategoryNo=&categoryNo=&viewDate=&isShowPopularPosts=false&from=postView
def get_fnguide_table(self, code):
url = re.get('http://comp.fnguide.com/SVO2/ASP/SVD_main.asp?pGB=1&gicode=A%s'%(code.strip()))
url = url.content
html = BeautifulSoup(url,'html.parser')
body = html.find('body')
try:
fn_body = body.find('div', {'class': 'fng_body asp_body'})
ur_table = fn_body.find('div', {'id': 'div15'})
table = ur_table.find('div', {'id': 'highlight_D_Y'})
tbody = table.find('tbody')
tr = tbody.find_all('tr')
Table = DataFrame()
except:
return {}
for i in tr:
''' 자료 항목 가져오기'''
category = i.find('span', {'class': 'txt_acd'})
if category == None:
category = i.find('th')
category = category.text.strip()
'''값 가져오기'''
value_list = []
j = i.find_all('td', {'class': 'r'})
for value in j:
temp = value.text.replace(',', '').strip()
try:
temp = float(temp)
value_list.append(temp)
except:
value_list.append(0)
Table['%s' % (category)] = value_list
''' 기간 가져오기 '''
thead = table.find('thead')
tr_2 = thead.find('tr', {'class': 'td_gapcolor2'}).find_all('th')
year_list = []
for i in tr_2:
try:
temp_year = i.find('span', {'class': 'txt_acd'}).text
except:
temp_year = i.text
temp_year = temp_year.replace("/",".")+".01"
year_list.append(temp_year)
Table.index = year_list
return Table.T.to_dict()
def crawl_fnguide(self, inFileName):
tableName = 'fnguide'
conn = sqlite3.connect(inFileName, isolation_level=None)
cursor = conn.cursor()
# 테이블 생성
create_sql = "CREATE TABLE IF NOT EXISTS "+tableName+" (CODE text, NAME text, ymd text, "
create_sql += " type text, sales REAL, net_business_profits REAL, business_profits REAL, business_profits_release REAL, "
create_sql += " net_profit REAL, significant_shareholder_net_profit REAL, "
create_sql += " none_significant_shareholder_net_profit REAL, total_assets REAL, total_debt REAL, "
create_sql += " total_ownership_interest REAL, equity_holdings REAL, none_equity_holdings REAL, capital REAL, "
create_sql += " debt_ratio REAL, reserve_ratio REAL, business_profits_ratio REAL, "
create_sql += " significant_shareholder_profits_ratio REAL, ROA REAL, ROE REAL, EPS REAL, BPS REAL, DPS REAL, "
create_sql += " PER REAL, PBR REAL, share_outstanding REAL, dividend_rate REAL)"
cursor.execute(create_sql)
# 키 생성
create_key = "CREATE INDEX IF NOT EXISTS "+tableName+"_idx on "+tableName+" (CODE, ymd) "
cursor.execute(create_key)
code_df = self.getStockInfo()
idx = 0
for item in code_df.values:
item_name = item[0]
item_code = item[1]
idx += 1
print(idx, item_code, item_name, 'http://comp.fnguide.com/SVO2/ASP/SVD_main.asp?pGB=1&gicode=A%s'%(item_code.strip()))
fnGuideData = self.get_fnguide_table(item_code)
"""
매출액: sales
순영업수익: net_business_profits REAL,
영업이익: business_profits
영업이익(발표기준): business_profits_release
당기순이익: net_profit
지배주주순이익: significant_shareholder_net_profit
비지배주주순이익: none_significant_shareholder_net_profit
자산총계: total_assets
부채총계: total_debt
자본총계: total_ownership_interest
지배주주지분: equity_holdings
비지배주주지분: none_equity_holdings
자본금: capital
부채비율: debt_ratio
유보율: reserve_ratio
영업이익률: business_profits_ratio
지배주주순이익률: significant_shareholder_profits_ratio
ROA: ROA
ROE: ROE
EPS(원): EPS
BPS(원): BPS
DPS(원): DPS
PER: PER
PBR: PBR
발행주식수: share_outstanding
배당수익률: dividend_rate
"""
for key_ymd in fnGuideData:
ymd = key_ymd.replace('(P)', '').replace('(E)', '')
if key_ymd.find('P') > 0:
type = 'P'
elif key_ymd.find('E') > 0:
type = 'E'
else:
type = ''
if '매출액' in fnGuideData[key_ymd]:
sales = fnGuideData[key_ymd]['매출액']
else:
sales = 0
if '순영업수익' in fnGuideData[key_ymd]:
net_business_profits = fnGuideData[key_ymd]['순영업수익']
else:
net_business_profits = 0
business_profits = fnGuideData[key_ymd]['영업이익']
business_profits_release = fnGuideData[key_ymd]['영업이익(발표기준)']
net_profit = fnGuideData[key_ymd]['당기순이익']
significant_shareholder_net_profit = fnGuideData[key_ymd]['지배주주순이익']
none_significant_shareholder_net_profit = fnGuideData[key_ymd]['비지배주주순이익']
total_assets = fnGuideData[key_ymd]['자산총계']
total_debt = fnGuideData[key_ymd]['부채총계']
total_ownership_interest = fnGuideData[key_ymd]['자본총계']
equity_holdings = fnGuideData[key_ymd]['지배주주지분']
none_equity_holdings = fnGuideData[key_ymd]['비지배주주지분']
capital = fnGuideData[key_ymd]['자본금']
debt_ratio = fnGuideData[key_ymd]['부채비율']
reserve_ratio = fnGuideData[key_ymd]['유보율']
business_profits_ratio = fnGuideData[key_ymd]['영업이익률']
significant_shareholder_profits_ratio = fnGuideData[key_ymd]['지배주주순이익률']
ROA = fnGuideData[key_ymd]['ROA']
ROE = fnGuideData[key_ymd]['ROE']
if 'EPS(원)' in fnGuideData[key_ymd]:
EPS = fnGuideData[key_ymd]['EPS(원)']
else:
EPS = fnGuideData[key_ymd]['EPS']
if 'BPS(원)' in fnGuideData[key_ymd]:
BPS = fnGuideData[key_ymd]['BPS(원)']
else:
BPS = fnGuideData[key_ymd]['BPS']
if 'DPS(원)' in fnGuideData[key_ymd]:
DPS = fnGuideData[key_ymd]['DPS(원)']
else:
DPS = fnGuideData[key_ymd]['DPS']
PER = fnGuideData[key_ymd]['PER']
PBR = fnGuideData[key_ymd]['PBR']
share_outstanding = fnGuideData[key_ymd]['발행주식수']
dividend_rate = fnGuideData[key_ymd]['배당수익률']
cursor.execute('SELECT * FROM '+tableName+' WHERE CODE=? and ymd=?', (item_code, ymd))
result = cursor.fetchone()
if result == None:
cursor.execute("INSERT INTO "+tableName+"(CODE, NAME, ymd, type, sales, net_business_profits, business_profits, business_profits_release, net_profit, significant_shareholder_net_profit, none_significant_shareholder_net_profit, total_assets, total_debt, total_ownership_interest, equity_holdings, none_equity_holdings, capital, debt_ratio, reserve_ratio, business_profits_ratio, significant_shareholder_profits_ratio, ROA, ROE, EPS, BPS, DPS, PER, PBR, share_outstanding, dividend_rate) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", (item_code, item_name, ymd, type, sales, net_business_profits, business_profits, business_profits_release, net_profit, significant_shareholder_net_profit, none_significant_shareholder_net_profit, total_assets, total_debt, total_ownership_interest, equity_holdings, none_equity_holdings, capital, debt_ratio, reserve_ratio, business_profits_ratio, significant_shareholder_profits_ratio, ROA, ROE, EPS, BPS, DPS, PER, PBR, share_outstanding, dividend_rate))
#else:
# cursor.execute("UPDATE "+tableName+" SET ymd=?, type=?, sales=?, net_business_profits=?, business_profits=?, business_profits_release=?, net_profit=?, significant_shareholder_net_profit=?, none_significant_shareholder_net_profit=?, total_assets=?, total_debt=?, total_ownership_interest=?, equity_holdings=?, none_equity_holdings=?, capital=?, debt_ratio=?, reserve_ratio=?, business_profits_ratio=?, significant_shareholder_profits_ratio=?, ROA=?, ROE=?, EPS=?, BPS=?, DPS=?, PER=?, PBR=?, share_outstanding=?, dividend_rate=? WHERE CODE=?", (ymd, type, sales, net_business_profits, business_profits, business_profits_release, net_profit, significant_shareholder_net_profit, none_significant_shareholder_net_profit, total_assets, total_debt, total_ownership_interest, equity_holdings, none_equity_holdings, capital, debt_ratio, reserve_ratio, business_profits_ratio, significant_shareholder_profits_ratio, ROA, ROE, EPS, BPS, DPS, PER, PBR, share_outstanding, dividend_rate, item_code))
cursor.close()
conn.close()
return
if __name__ == "__main__":
crawler = FnGuideCrawler()
#crawler.get_fnguide_table('155660')
PROJECT_HOME = os.path.join(os.path.dirname(os.path.join(os.path.dirname(os.path.join(os.path.dirname(os.path.join(os.path.dirname(__file__))))))))
inFnguideFileName = PROJECT_HOME + '/resources/fnguide.db'
crawler = FnGuideCrawler()
crawler.crawl_fnguide(inFnguideFileName)

View File

@@ -0,0 +1,367 @@
import json
import datetime
import requests
import sqlite3
import pandas as pd
class MetaCrawler:
header = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'}
limit_page_count = 10000
def __init__(self):
return
# 참고) http://blog.naver.com/PostView.nhn?blogId=koko8624&logNo=221288761509
def crawl_meterials(self, inFileName):
tableName = 'meta_1'
conn = sqlite3.connect(inFileName)
cursor = conn.cursor()
# 테이블 생성
cursor.execute("CREATE TABLE IF NOT EXISTS " + tableName + " (CODE text, NAME text, ymd text, close REAL, diff REAL, rate REAL)")
# 키 생성
create_key = "CREATE INDEX IF NOT EXISTS " + tableName + "_idx on " + tableName + " (CODE, ymd) "
cursor.execute(create_key)
inputs = []
inputs.append( {'NAME':'WTI', 'CODE':'OIL_CL', 'URL':'http://finance.naver.com/marketindex/worldDailyQuote.nhn?marketindexCd=OIL_CL&fdtc=2'} ) # WTI
inputs.append( {'NAME':'GOLD', 'CODE':'CMDT_GC', 'URL':'http://finance.naver.com/marketindex/worldDailyQuote.nhn?marketindexCd=CMDT_GC&fdtc=2'} ) # 국제 금
inputs.append({'NAME': 'COPPER', 'CODE': 'CMDT_CDY','URL': 'http://finance.naver.com/marketindex/worldDailyQuote.nhn?marketindexCd=CMDT_CDY&fdtc=2'}) # 구리
inputs.append({'NAME': 'NATURALGAS', 'CODE': 'CMDT_NG','URL': 'http://finance.naver.com/marketindex/worldDailyQuote.nhn?marketindexCd=CMDT_NG&fdtc=2'}) # 천연가스
inputs.append({'NAME': 'CORN', 'CODE': 'CMDT_C','URL': 'http://finance.naver.com/marketindex/worldDailyQuote.nhn?marketindexCd=CMDT_C&fdtc=2'}) # 국제 옥수수
inputs.append({'NAME': 'SOYBEAN', 'CODE': 'CMDT_S','URL': 'http://finance.naver.com/marketindex/worldDailyQuote.nhn?marketindexCd=CMDT_S&fdtc=2'}) # 국제 대두
for i in range(len(inputs)):
input = inputs[i]
NAME = input['NAME']
CODE = input['CODE']
cursor.execute('SELECT ymd FROM ' + tableName + ' WHERE CODE=? order by ymd desc', (CODE,))
result = cursor.fetchone()
if result == None:
lastDay = "1900.01.01"
else:
lastDay = result[0]
finish = False
for i in range(1, self.limit_page_count):
#html = pd.read_html(input['URL'] + '&page=%s' % i, header=0)
html = pd.read_html(requests.get(input['URL'] + '&page=%s' % i, headers=self.header).text)
# 마지막 페이지 까지 받기
if len(html[0].날짜.values) <= 1:
break
for j in range(0, len(html[0].values)):
item = html[0].values[j]
if item[0] <= lastDay:
finish = True
break
ymd = item[0] # 날짜
close = item[1] # 종가
diff = item[2] # 전일대비
rate = item[3] # 등락율
cursor.execute('SELECT * FROM ' + tableName + ' WHERE CODE=? and ymd=?', (CODE,ymd,))
result = cursor.fetchone()
if result == None:
cursor.execute("INSERT INTO " + tableName + "(CODE, NAME, ymd, close, diff, rate) VALUES(?, ?, ?, ?, ?, ?)", (CODE, NAME, ymd, close, diff, rate))
#else:
# cursor.execute("UPDATE " + tableName + " SET close=?, diff=?, rate=? WHERE CODE=? and ymd=?", (close, diff, rate, CODE, ymd))
print(CODE, NAME, ymd)
if finish:
break
conn.commit()
cursor.close()
conn.close()
return
# 참고) http://blog.naver.com/PostView.nhn?blogId=koko8624&logNo=221288761509
def crawl_exchange(self, inFileName):
tableName = 'meta_1'
conn = sqlite3.connect(inFileName)
cursor = conn.cursor()
# 테이블 생성
cursor.execute("CREATE TABLE IF NOT EXISTS "+tableName+" (CODE text, NAME text, ymd text, price REAL, diff REAL, cash_buy REAL, cash_sell REAL, transfer_buy REAL, transfer_sell REAL)")
# 키 생성
create_key = "CREATE INDEX IF NOT EXISTS " + tableName + "_idx on " + tableName + " (CODE, ymd) "
cursor.execute(create_key)
inputs = []
inputs.append( {'NAME':'USD', 'CODE':'FX_USDKRW', 'URL':'http://finance.naver.com/marketindex/exchangeDailyQuote.nhn?marketindexCd=FX_USDKRW'} ) # 미국 USD
inputs.append( {'NAME':'JPY', 'CODE':'FX_JPYKRW', 'URL':'http://finance.naver.com/marketindex/exchangeDailyQuote.nhn?marketindexCd=FX_JPYKRW'} ) # 일본 JPY
inputs.append( {'NAME':'EUR', 'CODE':'FX_EURKRW', 'URL':'http://finance.naver.com/marketindex/exchangeDailyQuote.nhn?marketindexCd=FX_EURKRW'} ) # 유럽연합 EUR'
inputs.append( {'NAME':'CNY', 'CODE':'FX_CNYKRW', 'URL':'http://finance.naver.com/marketindex/exchangeDailyQuote.nhn?marketindexCd=FX_CNYKRW'} ) # 중국 CNY
for i in range(len(inputs)):
input = inputs[i]
NAME = input['NAME']
CODE = input['CODE']
cursor.execute('SELECT ymd FROM ' + tableName + ' WHERE CODE=? order by ymd desc', (CODE,))
result = cursor.fetchone()
if result == None:
lastDay = "1900.01.01"
else:
lastDay = result[0]
finish = False
for i in range(1, self.limit_page_count):
#html = pd.read_html(input['URL'] + '&page=%s' % i, header=0)
html = pd.read_html(requests.get(input['URL'] + '&page=%s' % i, headers=self.header).text)
# 마지막 페이지 까지 받기
if len(html[0].날짜.values) <= 1:
break
for j in range(0, len(html[0].values)):
item = html[0].values[j]
if input['NAME'] in ('USD', 'JPY', 'EUR', 'CNY'):
if item[0] <= lastDay:
finish = True
break
ymd = item[0] # 날짜
price = item[1] # 매매기준율
diff = item[2] # 전일대비
cash_buy = item[3] # 현찰 사실 때
cash_sell = item[4] # 현찰 파실 때
transfer_buy = item[5] # 송금 사실 때
transfer_sell = item[6] # 송금 파실 때
cursor.execute('SELECT * FROM ' + tableName + ' WHERE CODE=? and ymd=?', (CODE,ymd,))
result = cursor.fetchone()
if result == None:
cursor.execute("INSERT INTO " + tableName + "(CODE, NAME, ymd, price, diff, cash_buy, cash_sell, transfer_buy, transfer_sell) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)", (CODE, NAME, ymd, price, diff, cash_buy, cash_sell, transfer_buy, transfer_sell))
#else:
# cursor.execute("UPDATE " + tableName + " SET price=?, diff=?, cash_buy=?, cash_sell=?, transfer_buy=?, transfer_sell=? WHERE CODE=? and ymd=?", (price, diff, cash_buy, cash_sell, transfer_buy, transfer_sell, CODE, ymd))
print(CODE, NAME, ymd)
if finish:
break
conn.commit()
cursor.close()
conn.close()
return
# 투자자별 매매동향 (Trading_Trend) 크롤링
# (pri, 개인)
# (for, 외국인)
# (ins, 기관합)
# (ins0, 금융투자)
# (ins1, 보험)
# (ins2, 투신 (사모))
# (ins3, 은행)
# (ins4, 기타금융기관)
# (ins5, 연기금 등)
# (cor, 기타법인)
# 참고) http://blog.naver.com/PostView.nhn?blogId=koko8624&logNo=221289696771&parentCategoryNo=&categoryNo=&viewDate=&isShowPopularPosts=false&from=postView
def crawl_trading_trend(self, inFileName):
tableName = 'meta_2'
conn = sqlite3.connect(inFileName)
cursor = conn.cursor()
# 테이블 생성
cursor.execute("CREATE TABLE IF NOT EXISTS "+tableName+" (ymd text PRIMARY KEY, pri integer, fori integer, ins integer, ins0 integer, ins1 integer, ins2 integer, ins3 integer, ins4 integer, ins5 integer, cor integer)")
cursor.execute('SELECT ymd FROM ' + tableName + ' order by ymd desc')
result = cursor.fetchone()
if result == None:
lastDay = "1900.01.01"
else:
lastDay = result[0]
today = datetime.datetime.now().strftime("%Y%m%d")
url = 'http://finance.naver.com/sise/investorDealTrendDay.nhn?bizdate='+today+'&sosok=&page='
previousDay = ""
finish = False
for i in range(1, self.limit_page_count):
#html = pd.read_html(url + str(i), header=0)
html = pd.read_html(requests.get(url + str(i), headers=self.header).text)
# 마지막 페이지 까지 받기
if len(html[0].날짜.values) <= 2:
break
for j in range(0, len(html[0].values)):
item = html[0].values[j]
if str(item[0]) == "nan":
continue
if "20" + item[0] <= lastDay or item[0] == previousDay:
finish = True
break
ymd = "20"+item[0]
pri = item[1] # 개인
fori = item[2] # 외국인
ins = item[3] # 기관합
ins0 = item[4] # 금융투자
ins1 = item[5] # 보험
ins2 = item[6] # 투신 (사모)
ins3 = item[7] # 은행
ins4 = item[8] # 기타금융기관
ins5 = item[9] # 연기금 등
cor = item[10] # 기타법인
cursor.execute('SELECT * FROM ' + tableName + ' WHERE ymd=?', (ymd,))
result = cursor.fetchone()
if result == None:
cursor.execute("INSERT INTO " + tableName + "(ymd, pri, fori, ins, ins0, ins1, ins2, ins3, ins4, ins5, cor) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", (ymd, pri, fori, ins, ins0, ins1, ins2, ins3, ins4, ins5, cor))
#else:
# cursor.execute("UPDATE " + tableName + " SET pri=?, fori=?, ins=?, ins0=?, ins1=?, ins2=?, ins3=?, ins4=?, ins5=?, cor=? WHERE ymd=?", (pri, fori, ins, ins0, ins1, ins2, ins3, ins4, ins5, cor, ymd))
print ("20"+item[0])
previousDay = html[0].values[2][0]
if finish:
break
conn.commit()
cursor.close()
conn.close()
return
# 증시자금동향 (신용잔고, 펀드자금 잔고) 크롤링
# 참고) http://blog.naver.com/PostView.nhn?blogId=koko8624&logNo=221290138187&parentCategoryNo=&categoryNo=&viewDate=&isShowPopularPosts=false&from=postView
def crawl_money_trend(self, inFileName):
tableName = 'meta_3'
conn = sqlite3.connect(inFileName)
cursor = conn.cursor()
cursor.execute("CREATE TABLE IF NOT EXISTS "+tableName+" (ymd text, dep1_1 integer, dep1_2 integer, dep2_1 integer, dep2_2 integer, dep3_1 integer, dep3_2 integer, dep4_1 integer, dep4_2 integer, dep5_1 integer, dep5_2 integer)")
# 키 생성
create_key = "CREATE INDEX IF NOT EXISTS "+tableName+"_idx on "+tableName+" (ymd) "
cursor.execute(create_key)
cursor.execute('SELECT * FROM ' + tableName + ' order by ymd desc')
result = cursor.fetchone()
if result == None:
lastDay = "1900.01.01"
else:
lastDay = result[0]
previousDay = ""
url = 'http://finance.naver.com/sise/sise_deposit.nhn?&page='
finish = False
for i in range(1, self.limit_page_count):
#html = pd.read_html(url + str(i), header=0, encoding='euc-kr')
html = pd.read_html(requests.get(url + str(i), headers=self.header).text, encoding='euc-kr')
# 마지막 페이지 까지 받기
if len(html[0].날짜.values) <= 10:
break
for j in range(0, len(html[0].values)):
item = html[0].values[j]
if str(item[0]) == "nan":
continue
if "20"+item[0] <= lastDay or item[0] == previousDay:
finish = True
break
meta = {
"ymd": "20"+item[0],
"dep1_1": item[1], # 고객예탁금 누적
"dep1_2": item[2], # 고객예탁금 당일
"dep2_1": item[3], # 신용잔고 누적
"dep2_2": item[4], # 신용잔고 당일
"dep3_1": item[5], # 주식형펀드 누적
"dep3_2": item[6], # 주식형펀드 당일
"dep4_1": item[7], # 혼합형펀드 누적
"dep4_2": item[8], # 혼합형펀드 당일
"dep5_1": item[9], # 채권형펀드 누적
"dep5_2": item[10]} # 채권형펀드 당일
cursor.execute('SELECT * FROM ' + tableName + ' WHERE ymd=?', (meta["ymd"],))
result = cursor.fetchone()
if result == None:
cursor.execute("INSERT INTO " + tableName + "(ymd, dep1_1, dep1_2, dep2_1, dep2_2, dep3_1, dep3_2, dep4_1, dep4_2, dep5_1, dep5_2) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", (meta["ymd"], meta["dep1_1"], meta["dep1_2"], meta["dep2_1"], meta["dep2_2"], meta["dep3_1"], meta["dep3_2"], meta["dep4_1"], meta["dep4_2"], meta["dep5_1"], meta["dep5_2"]))
#else:
# cursor.execute("UPDATE " + tableName + " SET dep1_1=?, dep1_2=?, dep2_1=?, dep2_2=?, dep3_1=?, dep3_2=?, dep4_1=?, dep4_2=?, dep5_1=?, dep5_2=? WHERE ymd=?", (meta["dep1_1"], meta["dep1_2"], meta["dep2_1"], meta["dep2_2"], meta["dep3_1"], meta["dep3_2"], meta["dep4_1"], meta["dep4_2"], meta["dep5_1"], meta["dep5_2"], meta["ymd"]))
print("20"+item[0])
if finish:
break
previousDay = html[0].values[2][0]
conn.commit()
cursor.close()
conn.close()
return
# 국내 시장금리 크롤링
# 참고) http://blog.naver.com/PostView.nhn?blogId=koko8624&logNo=221292348073&parentCategoryNo=&categoryNo=&viewDate=&isShowPopularPosts=false&from=postView
def crawl_interest_rates(self, inFileName):
tableName = 'meta_4'
conn = sqlite3.connect(inFileName)
cursor = conn.cursor()
# 테이블 생성
cursor.execute("CREATE TABLE IF NOT EXISTS " + tableName + " (CODE text, NAME text, ymd text, close REAL, diff REAL, rate REAL)")
# 키 생성
create_key = "CREATE INDEX IF NOT EXISTS "+tableName+"_idx on "+tableName+" (CODE, ymd) "
cursor.execute(create_key)
inputs = []
inputs.append({'NAME': '91일 CD금리', 'CODE': 'IRR_CD91', 'URL': 'http://finance.naver.com/marketindex/interestDailyQuote.nhn?marketindexCd=IRR_CD91'})
inputs.append({'NAME': '콜금리', 'CODE': 'IRR_CALL', 'URL': 'http://finance.naver.com/marketindex/interestDailyQuote.nhn?marketindexCd=IRR_CALL'})
inputs.append({'NAME': '국고채(3년)', 'CODE': 'IRR_GOVT03Y', 'URL': 'http://finance.naver.com/marketindex/interestDailyQuote.nhn?marketindexCd=IRR_GOVT03Y'})
inputs.append({'NAME': '회사채(3년)', 'CODE': 'IRR_CORP03Y', 'URL': 'http://finance.naver.com/marketindex/interestDailyQuote.nhn?marketindexCd=IRR_CORP03Y'})
for i in range(len(inputs)):
input = inputs[i]
NAME = input['NAME']
CODE = input['CODE']
cursor.execute('SELECT ymd FROM ' + tableName + ' WHERE CODE=? order by ymd desc', (CODE,))
result = cursor.fetchone()
if result == None:
lastDay = "1900.01.01"
else:
lastDay = result[0]
finish = False
for i in range(1, self.limit_page_count):
#html = pd.read_html(input['URL'] + '&page=%s' % i, header=0)
html = pd.read_html(requests.get(input['URL'] + '&page=%s' % i, headers=self.header).text)
ymd, close, diff, rate = "", 0.0, 0.0, 0.0
# 마지막 페이지 까지 받기
if len(html[0].날짜.values) <= 1:
break
for j in range(len(html[0].values)):
item = html[0].values[j]
if str(item[0]) == "nan":
continue
if item[0] <= lastDay:
finish = True
break
ymd = item[0]
close = item[1] # 종가
diff = item[2] # 전일대비
rate = item[3] # 등락율
cursor.execute('SELECT * FROM ' + tableName + ' WHERE CODE=? and ymd=?', (CODE, ymd,))
result = cursor.fetchone()
if result == None:
cursor.execute("INSERT INTO " + tableName + "(CODE, NAME, ymd, close, diff, rate) VALUES(?, ?, ?, ?, ?, ?)", (CODE, NAME, ymd, close, diff, rate))
#else:
# cursor.execute("UPDATE " + tableName + " SET close=?, diff=?, rate=? WHERE CODE=? and ymd=?", (close, diff, rate, CODE, ymd))
if finish:
break
print(NAME + " / " + ymd)
conn.commit()
cursor.close()
conn.close()
return

View File

@@ -0,0 +1,33 @@
class MovingAverage(object):
def __init__(self, max):
self.queue = []
self.max = max
def dequeue(self):
length = len(self.queue)
if length == 0 or length < self.max:
return -1
return self.queue.pop(0)
def enqueue(self, n):
length = len(self.queue)
if length == self.max:
self.dequeue()
self.queue.append(n)
pass
def sum(self):
sum = 0
for item in self.queue:
sum += item
return sum
def avg(self):
length = len(self.queue)
total = self.sum()
return round(total / length)
def print(self):
print(self.sum(), self.queue)

View File

@@ -0,0 +1,368 @@
# https://bigdata-sk.tistory.com/10
import pandas as pd
import re
import json
import sqlite3
import requests
import math
import time
# 닐짜 형식으로 바뀐 this_date값을 확인 가능
# 읽어온 날짜 정보를 date형식으로 바꿀 일이 계속 생기므로 이 기능을 함수로 정의해줌.
# 함수명은 date_format()
class StockCrawler:
header = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'}
historical_prices = None
special_pattern = None
fnGuideCrawler = None
limit_page_count = 10000
def __init__(self):
self.historical_prices = dict()
self.special_pattern = (
'[', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', ',', '.', '?', '"', ':', ';', '{', '}', '|', '<', '>',
']', '+', '-', '/', '=', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9')
return
def clean_str(self, string):
string = re.sub(r"\\", " ", string)
string = re.sub(r"\'", " ", string)
string = re.sub(r"\"", " ", string)
string = re.sub(r"`", " ", string)
string = re.sub(r"-", " ", string)
string = re.sub(r"\(.*?\)", " ", string)
string = re.sub(r" ", " ", string)
return string.strip().lower()
def getStockInfo(self):
#code_df = pd.read_html('http://kind.krx.co.kr/corpgeneral/corpList.do?method=download&searchType=13', header=0)[0]
code_df = pd.read_html(requests.get('http://kind.krx.co.kr/corpgeneral/corpList.do?method=download&searchType=13', headers=self.header).text)[0]
# code_df = pd.read_excel('../resources/stock/상장법인목록.xls')
# 종목코드가 6자리이기 때문에 6자리를 맞춰주기 위해 설정해줌
code_df.종목코드 = code_df.종목코드.map('{:06d}'.format)
# 우리가 필요한 것은 회사명과 종목코드이기 때문에 필요없는 column들은 제외해준다.
code_df = code_df[['회사명', '종목코드']]
# 한글로된 컬럼명을 영어로 바꿔준다.
code_df = code_df.rename(columns={'회사명': 'name', '종목코드': 'code'})
###print (code_df.head())
return code_df
# 종목 이름을 입력하면 종목에 해당하는 코드를 불러와
# 네이버 금융(http://finance.naver.com)에 넣어줌
def get_url(self, item_name, code_df):
code = code_df.query("name=='{}'".format(item_name))['code'].to_string(index=False).strip()
url = 'http://finance.naver.com/item/sise_day.nhn?code={code}'.format(code=code.strip())
return code, url
def date_format(slef, d):
d = str(d).replace('-', '.')
#yyyy = int(d.split('.')[0])
#mm = int(d.split('.')[1])
#dd = int(d.split('.')[2])
#this_date = dt.date(yyyy, mm, dd)
return d
def getCodeIndex(self, stocks, item_code):
for i, stock in enumerate(stocks):
if item_code == stock['CODE']:
return i
return -1
def crawl_etf_stocks(self, inFileName):
tableName = 'stock'
conn = sqlite3.connect(inFileName)
cursor = conn.cursor()
# 테이블 생성
cursor.execute("CREATE TABLE IF NOT EXISTS " + tableName + " (CODE text, NAME text, ymd text, close REAL, diff REAL, open REAL, high REAL, low REAL, volume REAL)")
# 키 생성
create_key = "CREATE INDEX IF NOT EXISTS " + tableName + "_idx on " + tableName + " (CODE, ymd) "
cursor.execute(create_key)
stocks = []
stocks.append({"NAME": 'KODEX 코스닥150선물인버스', "CODE": "251340"})
stocks.append({"NAME": 'KODEX 코스닥150 레버리지', "CODE": "233740"})
stocks.append({"NAME": 'KODEX 200선물인버스2X', "CODE": "252670"})
stocks.append({"NAME": 'KODEX 레버리지', "CODE": "122630"})
stocks.append({"NAME": 'KODEX 인버스', "CODE": "114800"})
stocks.append({"NAME": 'KODEX 중국본토CSI300', "CODE": "283580"})
stocks.append({"NAME": 'KODEX 심천ChiNext(합성)', "CODE": "256750"})
stocks.append({"NAME": 'KINDEX 블룸버그베트남VN30선물레버리지(H)', "CODE": "371130"})
stocks.append({"NAME": 'KODEX 미국S&P바이오(합성)', "CODE": "185680"})
stocks.append({"NAME": 'KODEX 미국S&P에너지(합성)', "CODE": "218420"})
stocks.append({"NAME": 'KODEX 골드선물(H)', "CODE": "132030"})
stocks.append({"NAME": 'KODEX 콩선물(H)', "CODE": "138920"})
stocks.append({"NAME": 'KODEX 3대농산물선물(H)', "CODE": "271060"})
stocks.append({"NAME": 'KODEX 건설', "CODE": "117700"})
stocks.append({"NAME": 'KODEX 헬스케어', "CODE": "266420"})
stocks.append({"NAME": 'KODEX 글로벌4차산업로보틱스(합성)', "CODE": "276990"})
stocks.append({"NAME": 'KODEX 바이오', "CODE": "244580"})
stocks.append({"NAME": 'KODEX 반도체', "CODE": "091160"})
stocks.append({"NAME": 'KODEX 보험', "CODE": "140700"})
stocks.append({"NAME": 'KODEX 필수소비재', "CODE": "266410"})
stocks.append({"NAME": 'KODEX 2차전지산업', "CODE": "305720"})
stocks.append({"NAME": 'KODEX 경기소비재', "CODE": "266390"})
stocks.append({"NAME": 'KODEX 철강', "CODE": "117680"})
stocks.append({"NAME": 'KODEX 에너지화학', "CODE": "117460"})
stocks.append({"NAME": 'KODEX 은행', "CODE": "091170"})
stocks.append({"NAME": 'TIGER 탄소효율그린뉴딜', "CODE": "376410"})
start_time = time.time()
for i, stock in enumerate(stocks):
print (i, stock["NAME"], stock["CODE"], (time.time()-start_time), "s")
start_time = time.time()
cursor.execute('SELECT * FROM ' + tableName + ' WHERE CODE=? order by ymd desc', (stock["CODE"],))
result = cursor.fetchone()
ymd = "2019.01.01"
if result != None:
ymd = result[0]
stock_data = self.crawl_specific_stock(stock["CODE"], ymd)
for item in stock_data:
cursor.execute('SELECT * FROM ' + tableName + ' WHERE CODE=? and ymd=?', (stock["CODE"],item['ymd'],))
result = cursor.fetchone()
if result == None:
cursor.execute("INSERT INTO " + tableName + "(CODE, NAME, ymd, close, diff, open, high, low, volume) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)", (stock["CODE"], stock["NAME"], item['ymd'], item['close'], item['diff'], item['open'], item['high'], item['low'], item['volume']))
#else:
# cursor.execute("UPDATE " + tableName + " SET close=?, diff=?, open=?, high=?, low=?, volume=? WHERE CODE=? and ymd=?", (item['close'], item['diff'], item['open'], item['high'], item['low'], item['volume'], stock["CODE"], item['ymd']))
conn.commit()
cursor.close()
conn.close()
return
def crawl_stocks(self, inFileName):
tableName = 'stock'
conn = sqlite3.connect(inFileName)
cursor = conn.cursor()
# 테이블 생성
cursor.execute("CREATE TABLE IF NOT EXISTS " + tableName + " (CODE text, NAME text, ymd text, close REAL, diff REAL, open REAL, high REAL, low REAL, volume REAL)")
# 키 생성
create_key = "CREATE INDEX IF NOT EXISTS " + tableName + "_idx on " + tableName + " (CODE, ymd) "
cursor.execute(create_key)
conn.commit()
cursor.close()
conn.close()
code_df = self.getStockInfo()
items = code_df.values
start_time = time.time()
idx = 0
for item in items:
conn = sqlite3.connect(inFileName)
cursor = conn.cursor()
idx += 1
item_name = item[0]
item_code = item[1]
cursor.execute('SELECT ymd FROM ' + tableName + ' WHERE CODE=? order by ymd desc', (item_code,))
result = cursor.fetchone()
stock = {"CODE": item_code, "NAME": item_name}
ymd = "2020.01.01"
if result != None:
ymd = result[0]
stock_data = self.crawl_specific_stock(item_code, ymd)
for item in stock_data:
cursor.execute('SELECT * FROM ' + tableName + ' WHERE CODE=? and ymd=?', (stock["CODE"],item['ymd'],))
result = cursor.fetchone()
if result == None:
cursor.execute("INSERT INTO " + tableName + "(CODE, NAME, ymd, close, diff, open, high, low, volume) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)", (stock["CODE"], stock["NAME"], item['ymd'], item['close'], item['diff'], item['open'], item['high'], item['low'], item['volume']))
#else:
# cursor.execute("UPDATE " + tableName + " SET close=?, diff=?, open=?, high=?, low=?, volume=? WHERE CODE=? and ymd=?", (item['close'], item['diff'], item['open'], item['high'], item['low'], item['volume'], stock["CODE"], item['ymd']))
conn.commit()
cursor.close()
conn.close()
print(idx, item_name, item_code, (time.time() - start_time), "s")
start_time = time.time()
return
def get_data(self, code, lastDay):
url = 'http://finance.naver.com/item/sise_day.nhn?code={code}'.format(code=code.strip())
stock = []
# 일자 데이터를 담을 df라는 DataFrame 정의
df = pd.DataFrame()
date_set = set()
lastPage = False
# 1페이지에서 1000페이지의 데이터만 가져오기
for page in range(1, self.limit_page_count):
# 최근 상장 기업의 마지막 반복되는 페이지를 제외시킨다.
pg_url = '{url}&page={page}'.format(url=url, page=page)
#html = pd.read_html(pg_url, header=0)
html = pd.read_html(requests.get(pg_url, headers=self.header).text)
for date in html[0].날짜.values:
if type(date) is str:
if date in date_set:
lastPage = True
break
date_set.add(date)
if date == lastDay:
lastPage = True
df = df.append(html[0], ignore_index=True)
break
df = df.append(html[0], ignore_index=True)
if lastPage:
print("\t- lastpage:", page)
break
# df.dropna()를 이용해 결측값 있는 행 제거
df = df.dropna()
# 상위 5개 데이터 확인하기
###print (df.head())
# 한글로 된 컬럼명을 영어로 바꿔줌
df = df.rename(columns={'날짜': 'date', '종가': 'close', '전일비': 'diff', '시가': 'open', '고가': 'high', '저가': 'low', '거래량': 'volume'})
# 데이터의 타입을 int형으로 바꿔줌
df[['close', 'diff', 'open', 'high', 'low', 'volume']] = df[['close', 'diff', 'open', 'high', 'low', 'volume']].astype(int)
for values in df.values:
day = str(values[0]).split(' ')[0]
if lastDay == day:
break
stock.append({
"ymd": day,
df.columns[1]: values[1],
df.columns[2]: values[2],
df.columns[3]: values[3],
df.columns[4]: values[4],
df.columns[5]: values[5],
df.columns[6]: values[6],
})
# stock = sorted(stock, key=lambda x: x['ymd'], reverse=True)
stock = sorted(stock, key=lambda x: x['ymd'])
return stock
def crawl_specific_stock(self, code, ymd):
# 데이터 수집
stock = self.get_data(code, ymd)
# 이동 평균 계산
#self.get_moving_avg(stock)
return stock
def update(self, inFileName, outFileName):
"""
Full json 데이터를 db에 import 시킴
inFileName = PROJECT_HOME + '/resources/stock.json.full'
outFileName = PROJECT_HOME + '/resources/stock.db'
crawler = StockCrawler()
crawler.update(inFileName, outFileName)
:param inFileName:
:param outFileName:
:return:
"""
tableName = 'stock'
conn = sqlite3.connect(outFileName, isolation_level=None)
cursor = conn.cursor()
cursor.execute("CREATE TABLE IF NOT EXISTS " + tableName + " (CODE text PRIMARY KEY, NAME text, PRICE text, MACD text, STOCHASTIC text, ICHIMOKU text, RSI text, BOLINGERBAND text)")
idx = 0
inFp = open(inFileName, 'r')
for line in inFp.readlines():
if line:
idx += 1
stock = json.loads(line)
print(idx, stock["CODE"], stock["NAME"])
text = json.dumps(stock["PRICE"], ensure_ascii=False)
cursor.execute('SELECT * FROM ' + tableName + ' WHERE CODE=?', (stock["CODE"],))
result = cursor.fetchone()
if result == None:
cursor.execute("INSERT INTO " + tableName + "(CODE, NAME, PRICE) VALUES(?, ?, ?)", (stock["CODE"], stock["NAME"], text))
else:
cursor.execute("UPDATE " + tableName + " SET PRICE=? WHERE CODE=?", (text, stock["CODE"]))
return
def saveIndex(self, code, inFileName, outFileName):
tableName = 'stock'
conn = sqlite3.connect(outFileName)
cursor = conn.cursor()
cursor.execute("CREATE TABLE IF NOT EXISTS " + tableName + " (CODE text PRIMARY KEY, NAME text, PRICE text, MACD text, STOCHASTIC text, ICHIMOKU text, RSI text, BOLINGERBAND text)")
stock = {"NAME": code, "CODE": code}
lastDay = ""
cursor.execute('SELECT * FROM ' + tableName + ' WHERE CODE=?', (stock["CODE"],))
result = cursor.fetchone()
if result != None:
stock["PRICE"] = json.loads(result[2])
lastDay = stock["PRICE"][len(stock["PRICE"]) - 1]["DATE"]
with open(inFileName, "r", encoding="utf-8") as inFp:
for line in inFp:
line = line.strip()
if line[0] == "#":
continue
arr = line.split("\t")
if arr[0] == lastDay:
break
price = {"DATE": arr[0], "close": float(arr[1]), "diff": float(arr[6].replace("%", "")), "open": float(arr[2]), "high": float(arr[3]), "low": float(arr[4]), "volume": 0}
price['avg3'] = 0
price['avg5'] = 0
price['avg7'] = 0
price['avg10'] = 0
price['avg20'] = 0
price['avg30'] = 0
price['avg60'] = 0
price['avg90'] = 0
price['avg100'] = 0
price['avg120'] = 0
price['avg150'] = 0
price['avg180'] = 0
price['avg200'] = 0
price['avg240'] = 0
stock["PRICE"].append(price)
stock["PRICE"] = sorted(stock["PRICE"], key=lambda x: x['DATE'])
# self.get_moving_avg(stock)
text = json.dumps(stock['PRICE'], ensure_ascii=False)
cursor.execute('SELECT * FROM ' + tableName + ' WHERE CODE=?', (stock["CODE"],))
result = cursor.fetchone()
if result == None:
cursor.execute("INSERT INTO " + tableName + "(CODE, NAME, PRICE, MACD, STOCHASTIC, ICHIMOKU, RSI) VALUES(?, ?, ?, ?, ?, ?, ?)", (stock["CODE"], stock["NAME"], text, "[{}]", "[{}]", "[{}]", "[{}]"))
else:
cursor.execute("UPDATE " + tableName + " SET PRICE=?, MACD=?, STOCHASTIC=?, ICHIMOKU=?, RSI=? WHERE CODE=?", (text, "[{}]", "[{}]", "[{}]", "[{}]", stock["CODE"]))
conn.commit()
cursor.close()
conn.close()
return

View File

@@ -0,0 +1,365 @@
364,1186,1339,46.97
363,1086,1439,43.01
362,805,1720,31.88
361,1121,1404,44.40
360,674,1851,26.69
359,260,2265,10.30
358,1616,909,64.00
357,341,2184,13.50
356,1179,1346,46.69
355,1499,1026,59.37
354,1801,724,71.33
353,925,1600,36.63
352,532,1993,21.07
351,1248,1277,49.43
350,1092,1433,43.25
349,1292,1233,51.17
348,1253,1272,49.62
347,1070,1455,42.38
346,1966,559,77.86
345,1436,1089,56.87
344,786,1739,31.13
343,1365,1160,54.06
342,1181,1344,46.77
341,1147,1378,45.43
340,1319,1206,52.24
339,904,1621,35.80
338,748,1777,29.62
337,533,1992,21.11
336,1024,1501,40.55
335,458,2067,18.14
334,395,2130,15.64
333,923,1602,36.55
332,548,1977,21.70
331,1020,1505,40.40
330,1736,789,68.75
329,1300,1225,51.49
328,1564,961,61.94
327,999,1526,39.56
326,1642,883,65.03
325,880,1645,34.85
324,1009,1516,39.96
323,810,1715,32.08
322,624,1901,24.71
321,614,1911,24.32
320,634,1891,25.11
319,873,1652,34.57
318,1320,1205,52.28
317,1416,1109,56.08
316,710,1815,28.12
315,830,1695,32.87
314,358,2167,14.18
313,1379,1146,54.61
312,1871,654,74.10
311,1634,891,64.71
310,420,2105,16.63
309,1605,920,63.56
308,1486,1039,58.85
307,914,1611,36.20
306,1647,878,65.23
305,646,1879,25.58
304,1526,999,60.44
303,995,1530,39.41
302,1137,1388,45.03
301,1059,1466,41.94
300,991,1534,39.25
299,1205,1320,47.72
298,734,1791,29.07
297,1388,1137,54.97
296,1026,1499,40.63
295,1394,1131,55.21
294,1021,1504,40.44
293,1152,1373,45.62
292,437,2088,17.31
291,1154,1371,45.70
290,1269,1256,50.26
289,855,1670,33.86
288,1153,1372,45.66
287,1100,1425,43.56
286,858,1667,33.98
285,777,1748,30.77
284,797,1728,31.56
283,855,1670,33.86
282,1343,1182,53.19
281,1351,1174,53.50
280,1314,1211,52.04
279,735,1790,29.11
278,904,1621,35.80
277,1253,1272,49.62
276,935,1590,37.03
275,1048,1477,41.50
274,916,1609,36.28
273,359,2166,14.22
272,892,1633,35.33
271,1320,1205,52.28
270,727,1798,28.79
269,1702,823,67.41
268,1612,913,63.84
267,1182,1343,46.81
266,1470,1055,58.22
265,872,1653,34.53
264,1270,1255,50.30
263,687,1838,27.21
262,435,2090,17.23
261,1260,1265,49.90
260,1375,1150,54.46
259,1297,1228,51.37
258,653,1872,25.86
257,639,1886,25.31
256,1721,804,68.16
255,1295,1230,51.29
254,1213,1312,48.04
253,863,1662,34.18
252,1360,1165,53.86
251,656,1869,25.98
250,682,1843,27.01
249,880,1645,34.85
248,278,2247,11.01
247,1975,550,78.22
246,1364,1161,54.02
245,1142,1383,45.23
244,774,1751,30.65
243,1001,1524,39.64
242,873,1652,34.57
241,902,1623,35.72
240,1323,1202,52.40
239,1390,1135,55.05
238,1062,1463,42.06
237,1162,1363,46.02
236,717,1808,28.40
235,895,1630,35.45
234,794,1731,31.45
233,987,1538,39.09
232,297,2228,11.76
231,1538,987,60.91
230,1138,1387,45.07
229,760,1765,30.10
228,1706,819,67.56
227,1169,1356,46.30
226,1274,1251,50.46
225,617,1908,24.44
224,794,1731,31.45
223,544,1981,21.54
222,1659,866,65.70
221,1587,938,62.85
220,1173,1352,46.46
219,1278,1247,50.61
218,1043,1482,41.31
217,1141,1384,45.19
216,1728,797,68.44
215,906,1619,35.88
214,563,1962,22.30
213,1427,1098,56.51
212,1271,1254,50.34
211,1114,1411,44.12
210,945,1580,37.43
209,1358,1167,53.78
208,1041,1484,41.23
207,1150,1375,45.54
206,1035,1490,40.99
205,1195,1330,47.33
204,901,1624,35.68
203,1307,1218,51.76
202,1222,1303,48.40
201,1323,1202,52.40
200,1222,1303,48.40
199,1185,1340,46.93
198,1174,1351,46.50
197,956,1569,37.86
196,1134,1391,44.91
195,1109,1416,43.92
194,1440,1085,57.03
193,771,1754,30.53
192,1094,1431,43.33
191,1191,1334,47.17
190,1189,1336,47.09
189,947,1578,37.50
188,536,1989,21.23
187,903,1622,35.76
186,814,1711,32.24
185,927,1598,36.71
184,1178,1347,46.65
183,1632,893,64.63
182,1394,1131,55.21
181,1381,1144,54.69
180,1147,1378,45.43
179,591,1934,23.41
178,1344,1181,53.23
177,1191,1334,47.17
176,695,1830,27.52
175,1527,998,60.48
174,1239,1286,49.07
173,621,1904,24.59
172,672,1853,26.61
171,1581,944,62.61
170,1317,1208,52.16
169,1230,1295,48.71
168,1352,1173,53.54
167,1284,1241,50.85
166,1311,1214,51.92
165,1099,1426,43.52
164,1217,1308,48.20
163,1115,1410,44.16
162,867,1658,34.34
161,941,1584,37.27
160,848,1677,33.58
159,1320,1205,52.28
158,1197,1328,47.41
157,1023,1502,40.51
156,1078,1447,42.69
155,1345,1180,53.27
154,1226,1299,48.55
153,1171,1354,46.38
152,835,1690,33.07
151,1146,1379,45.39
150,793,1732,31.41
149,946,1579,37.47
148,1240,1285,49.11
147,1265,1260,50.10
146,920,1605,36.44
145,1200,1325,47.52
144,997,1528,39.49
143,987,1538,39.09
142,1116,1409,44.20
141,1218,1307,48.24
140,868,1657,34.38
139,475,2050,18.81
138,999,1526,39.56
137,1590,935,62.97
136,1458,1067,57.74
135,1001,1524,39.64
134,1221,1304,48.36
133,1020,1505,40.40
132,809,1716,32.04
131,1505,1020,59.60
130,627,1898,24.83
129,1258,1267,49.82
128,1199,1326,47.49
127,601,1924,23.80
126,1261,1264,49.94
125,827,1698,32.75
124,1270,1255,50.30
123,617,1908,24.44
122,1074,1451,42.53
121,893,1632,35.37
120,1766,759,69.94
119,1495,1030,59.21
118,914,1611,36.20
117,805,1720,31.88
116,675,1850,26.73
115,890,1635,35.25
114,1036,1489,41.03
113,514,2011,20.36
112,394,2131,15.60
111,1912,613,75.72
110,389,2136,15.41
109,320,2205,12.67
108,1889,636,74.81
107,1940,585,76.83
106,1088,1437,43.09
105,865,1660,34.26
104,1662,863,65.82
103,1132,1393,44.83
102,1238,1287,49.03
101,1597,928,63.25
100,1036,1489,41.03
99,1307,1218,51.76
98,1046,1479,41.43
97,1043,1482,41.31
96,777,1748,30.77
95,922,1603,36.51
94,1359,1166,53.82
93,663,1862,26.26
92,1542,983,61.07
91,976,1549,38.65
90,707,1818,28.00
89,1207,1318,47.80
88,819,1706,32.44
87,1026,1499,40.63
86,1335,1190,52.87
85,530,1995,20.99
84,1599,926,63.33
83,1408,1117,55.76
82,533,1992,21.11
81,691,1834,27.37
80,343,2182,13.58
79,2095,430,82.97
78,1015,1510,40.20
77,804,1721,31.84
76,1967,558,77.90
75,1895,630,75.05
74,1399,1126,55.41
73,1015,1510,40.20
72,1193,1332,47.25
71,870,1655,34.46
70,731,1794,28.95
69,1094,1431,43.33
68,1401,1124,55.49
67,1583,942,62.69
66,772,1753,30.57
65,802,1723,31.76
64,617,1908,24.44
63,1050,1475,41.58
62,1643,882,65.07
61,588,1937,23.29
60,599,1926,23.72
59,770,1755,30.50
58,1411,1114,55.88
57,997,1528,39.49
56,494,2031,19.56
55,1235,1290,48.91
54,1922,603,76.12
53,1483,1042,58.73
52,967,1558,38.30
51,691,1834,27.37
50,938,1587,37.15
49,1460,1065,57.82
48,1067,1458,42.26
47,1063,1462,42.10
46,1212,1313,48.00
45,794,1731,31.45
44,494,2031,19.56
43,1547,978,61.27
42,278,2247,11.01
41,2035,490,80.59
40,2081,444,82.42
39,1839,686,72.83
38,1541,984,61.03
37,1372,1153,54.34
36,730,1795,28.91
35,1631,894,64.59
34,1186,1339,46.97
33,980,1545,38.81
32,1117,1408,44.24
31,1078,1447,42.69
30,910,1615,36.04
29,1407,1118,55.72
28,553,1972,21.90
27,1243,1282,49.23
26,1035,1490,40.99
25,1106,1419,43.80
24,1290,1235,51.09
23,1135,1390,44.95
22,1184,1341,46.89
21,1553,972,61.50
20,1294,1231,51.25
19,1321,1204,52.32
18,1314,1211,52.04
17,787,1738,31.17
16,1121,1404,44.40
15,1690,835,66.93
14,700,1825,27.72
13,627,1898,24.83
12,1754,771,69.47
11,919,1606,36.40
10,1051,1474,41.62
9,557,1968,22.06
8,594,1931,23.52
7,1281,1244,50.73
6,2005,520,79.41
5,926,1599,36.67
4,476,2049,18.85
3,325,2200,12.87
2,1516,1009,60.04
1,309,2216,12.24
0,2134,391,84.51

View File

@@ -0,0 +1,365 @@
364,1186,1339,46.97
363,1086,1439,43.01
362,805,1720,31.88
361,1121,1404,44.40
360,674,1851,26.69
359,260,2265,10.30
358,1616,909,64.00
357,341,2184,13.50
356,1179,1346,46.69
355,1499,1026,59.37
354,1801,724,71.33
353,925,1600,36.63
352,532,1993,21.07
351,1248,1277,49.43
350,1092,1433,43.25
349,1292,1233,51.17
348,1253,1272,49.62
347,1070,1455,42.38
346,1966,559,77.86
345,1436,1089,56.87
344,786,1739,31.13
343,1365,1160,54.06
342,1181,1344,46.77
341,1147,1378,45.43
340,1319,1206,52.24
339,904,1621,35.80
338,748,1777,29.62
337,533,1992,21.11
336,1024,1501,40.55
335,458,2067,18.14
334,395,2130,15.64
333,923,1602,36.55
332,548,1977,21.70
331,1020,1505,40.40
330,1736,789,68.75
329,1300,1225,51.49
328,1564,961,61.94
327,999,1526,39.56
326,1642,883,65.03
325,880,1645,34.85
324,1009,1516,39.96
323,810,1715,32.08
322,624,1901,24.71
321,614,1911,24.32
320,634,1891,25.11
319,873,1652,34.57
318,1320,1205,52.28
317,1416,1109,56.08
316,710,1815,28.12
315,830,1695,32.87
314,358,2167,14.18
313,1379,1146,54.61
312,1871,654,74.10
311,1634,891,64.71
310,420,2105,16.63
309,1605,920,63.56
308,1486,1039,58.85
307,914,1611,36.20
306,1647,878,65.23
305,646,1879,25.58
304,1526,999,60.44
303,995,1530,39.41
302,1137,1388,45.03
301,1059,1466,41.94
300,991,1534,39.25
299,1205,1320,47.72
298,734,1791,29.07
297,1388,1137,54.97
296,1026,1499,40.63
295,1394,1131,55.21
294,1021,1504,40.44
293,1152,1373,45.62
292,437,2088,17.31
291,1154,1371,45.70
290,1269,1256,50.26
289,855,1670,33.86
288,1153,1372,45.66
287,1100,1425,43.56
286,858,1667,33.98
285,777,1748,30.77
284,797,1728,31.56
283,855,1670,33.86
282,1343,1182,53.19
281,1351,1174,53.50
280,1314,1211,52.04
279,735,1790,29.11
278,904,1621,35.80
277,1253,1272,49.62
276,935,1590,37.03
275,1048,1477,41.50
274,916,1609,36.28
273,359,2166,14.22
272,892,1633,35.33
271,1320,1205,52.28
270,727,1798,28.79
269,1702,823,67.41
268,1612,913,63.84
267,1182,1343,46.81
266,1470,1055,58.22
265,872,1653,34.53
264,1270,1255,50.30
263,687,1838,27.21
262,435,2090,17.23
261,1260,1265,49.90
260,1375,1150,54.46
259,1297,1228,51.37
258,653,1872,25.86
257,639,1886,25.31
256,1721,804,68.16
255,1295,1230,51.29
254,1213,1312,48.04
253,863,1662,34.18
252,1360,1165,53.86
251,656,1869,25.98
250,682,1843,27.01
249,880,1645,34.85
248,278,2247,11.01
247,1975,550,78.22
246,1364,1161,54.02
245,1142,1383,45.23
244,774,1751,30.65
243,1001,1524,39.64
242,873,1652,34.57
241,902,1623,35.72
240,1323,1202,52.40
239,1390,1135,55.05
238,1062,1463,42.06
237,1162,1363,46.02
236,717,1808,28.40
235,895,1630,35.45
234,794,1731,31.45
233,987,1538,39.09
232,297,2228,11.76
231,1538,987,60.91
230,1138,1387,45.07
229,760,1765,30.10
228,1706,819,67.56
227,1169,1356,46.30
226,1274,1251,50.46
225,617,1908,24.44
224,794,1731,31.45
223,544,1981,21.54
222,1659,866,65.70
221,1587,938,62.85
220,1173,1352,46.46
219,1278,1247,50.61
218,1043,1482,41.31
217,1141,1384,45.19
216,1728,797,68.44
215,906,1619,35.88
214,563,1962,22.30
213,1427,1098,56.51
212,1271,1254,50.34
211,1114,1411,44.12
210,945,1580,37.43
209,1358,1167,53.78
208,1041,1484,41.23
207,1150,1375,45.54
206,1035,1490,40.99
205,1195,1330,47.33
204,901,1624,35.68
203,1307,1218,51.76
202,1222,1303,48.40
201,1323,1202,52.40
200,1222,1303,48.40
199,1185,1340,46.93
198,1174,1351,46.50
197,956,1569,37.86
196,1134,1391,44.91
195,1109,1416,43.92
194,1440,1085,57.03
193,771,1754,30.53
192,1094,1431,43.33
191,1191,1334,47.17
190,1189,1336,47.09
189,947,1578,37.50
188,536,1989,21.23
187,903,1622,35.76
186,814,1711,32.24
185,927,1598,36.71
184,1178,1347,46.65
183,1632,893,64.63
182,1394,1131,55.21
181,1381,1144,54.69
180,1147,1378,45.43
179,591,1934,23.41
178,1344,1181,53.23
177,1191,1334,47.17
176,695,1830,27.52
175,1527,998,60.48
174,1239,1286,49.07
173,621,1904,24.59
172,672,1853,26.61
171,1581,944,62.61
170,1317,1208,52.16
169,1230,1295,48.71
168,1352,1173,53.54
167,1284,1241,50.85
166,1311,1214,51.92
165,1099,1426,43.52
164,1217,1308,48.20
163,1115,1410,44.16
162,867,1658,34.34
161,941,1584,37.27
160,848,1677,33.58
159,1320,1205,52.28
158,1197,1328,47.41
157,1023,1502,40.51
156,1078,1447,42.69
155,1345,1180,53.27
154,1226,1299,48.55
153,1171,1354,46.38
152,835,1690,33.07
151,1146,1379,45.39
150,793,1732,31.41
149,946,1579,37.47
148,1240,1285,49.11
147,1265,1260,50.10
146,920,1605,36.44
145,1200,1325,47.52
144,997,1528,39.49
143,987,1538,39.09
142,1116,1409,44.20
141,1218,1307,48.24
140,868,1657,34.38
139,475,2050,18.81
138,999,1526,39.56
137,1590,935,62.97
136,1458,1067,57.74
135,1001,1524,39.64
134,1221,1304,48.36
133,1020,1505,40.40
132,809,1716,32.04
131,1505,1020,59.60
130,627,1898,24.83
129,1258,1267,49.82
128,1199,1326,47.49
127,601,1924,23.80
126,1261,1264,49.94
125,827,1698,32.75
124,1270,1255,50.30
123,617,1908,24.44
122,1074,1451,42.53
121,893,1632,35.37
120,1766,759,69.94
119,1495,1030,59.21
118,914,1611,36.20
117,805,1720,31.88
116,675,1850,26.73
115,890,1635,35.25
114,1036,1489,41.03
113,514,2011,20.36
112,394,2131,15.60
111,1912,613,75.72
110,389,2136,15.41
109,320,2205,12.67
108,1889,636,74.81
107,1940,585,76.83
106,1088,1437,43.09
105,865,1660,34.26
104,1662,863,65.82
103,1132,1393,44.83
102,1238,1287,49.03
101,1597,928,63.25
100,1036,1489,41.03
99,1307,1218,51.76
98,1046,1479,41.43
97,1043,1482,41.31
96,777,1748,30.77
95,922,1603,36.51
94,1359,1166,53.82
93,663,1862,26.26
92,1542,983,61.07
91,976,1549,38.65
90,707,1818,28.00
89,1207,1318,47.80
88,819,1706,32.44
87,1026,1499,40.63
86,1335,1190,52.87
85,530,1995,20.99
84,1599,926,63.33
83,1408,1117,55.76
82,533,1992,21.11
81,691,1834,27.37
80,343,2182,13.58
79,2095,430,82.97
78,1015,1510,40.20
77,804,1721,31.84
76,1967,558,77.90
75,1895,630,75.05
74,1399,1126,55.41
73,1015,1510,40.20
72,1193,1332,47.25
71,870,1655,34.46
70,731,1794,28.95
69,1094,1431,43.33
68,1401,1124,55.49
67,1583,942,62.69
66,772,1753,30.57
65,802,1723,31.76
64,617,1908,24.44
63,1050,1475,41.58
62,1643,882,65.07
61,588,1937,23.29
60,599,1926,23.72
59,770,1755,30.50
58,1411,1114,55.88
57,997,1528,39.49
56,494,2031,19.56
55,1235,1290,48.91
54,1922,603,76.12
53,1483,1042,58.73
52,967,1558,38.30
51,691,1834,27.37
50,938,1587,37.15
49,1460,1065,57.82
48,1067,1458,42.26
47,1063,1462,42.10
46,1212,1313,48.00
45,794,1731,31.45
44,494,2031,19.56
43,1547,978,61.27
42,278,2247,11.01
41,2035,490,80.59
40,2081,444,82.42
39,1839,686,72.83
38,1541,984,61.03
37,1372,1153,54.34
36,730,1795,28.91
35,1631,894,64.59
34,1186,1339,46.97
33,980,1545,38.81
32,1117,1408,44.24
31,1078,1447,42.69
30,910,1615,36.04
29,1407,1118,55.72
28,553,1972,21.90
27,1243,1282,49.23
26,1035,1490,40.99
25,1106,1419,43.80
24,1290,1235,51.09
23,1135,1390,44.95
22,1184,1341,46.89
21,1553,972,61.50
20,1294,1231,51.25
19,1321,1204,52.32
18,1314,1211,52.04
17,787,1738,31.17
16,1121,1404,44.40
15,1690,835,66.93
14,700,1825,27.72
13,627,1898,24.83
12,1754,771,69.47
11,919,1606,36.40
10,1051,1474,41.62
9,557,1968,22.06
8,594,1931,23.52
7,1281,1244,50.73
6,2005,520,79.41
5,926,1599,36.67
4,476,2049,18.85
3,325,2200,12.87
2,1516,1009,60.04
1,309,2216,12.24
0,2134,391,84.51