init
This commit is contained in:
|
Can't render this file because it is too large.
|
712
stockpredictor/analysis/AnalyzerSqlite.py
Normal file
712
stockpredictor/analysis/AnalyzerSqlite.py
Normal 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...")
|
||||
@@ -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
|
||||
560
stockpredictor/analysis/Common.old.py
Normal file
560
stockpredictor/analysis/Common.old.py
Normal 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 ""
|
||||
@@ -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 ""
|
||||
@@ -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__":
|
||||
|
||||
@@ -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()
|
||||
|
||||
71
stockpredictor/crawler/sQLite/Crawler.py
Normal file
71
stockpredictor/crawler/sQLite/Crawler.py
Normal 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...")
|
||||
220
stockpredictor/crawler/sQLite/FnGuideCrawler.py
Normal file
220
stockpredictor/crawler/sQLite/FnGuideCrawler.py
Normal 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)
|
||||
367
stockpredictor/crawler/sQLite/MetaCrawler.py
Normal file
367
stockpredictor/crawler/sQLite/MetaCrawler.py
Normal 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
|
||||
33
stockpredictor/crawler/sQLite/MovingAverage.py
Normal file
33
stockpredictor/crawler/sQLite/MovingAverage.py
Normal 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)
|
||||
368
stockpredictor/crawler/sQLite/StockCrawler.py
Normal file
368
stockpredictor/crawler/sQLite/StockCrawler.py
Normal 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
|
||||
365
stockpredictor/crawler/sQLite/inout.cvs
Normal file
365
stockpredictor/crawler/sQLite/inout.cvs
Normal 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
|
||||
365
stockpredictor/crawler/toSQLite/inout.cvs
Normal file
365
stockpredictor/crawler/toSQLite/inout.cvs
Normal 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
|
||||
Reference in New Issue
Block a user