This commit is contained in:
dsyoon
2024-04-26 07:47:48 +09:00
parent 3bbfdf2f7a
commit d5e5316fce
25 changed files with 1699 additions and 3665 deletions

View File

@@ -1,594 +0,0 @@
import os
import time
import shutil
import matplotlib.pyplot as plt
import datetime
import sqlite3
import math
from math import nan
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
from matplotlib import rc
import pandas as pd
import numpy as np
from stock.analysis.JSDPattern_simulation import JSDPattern_simulation
from hts.BuySell_Daily import BuySell_Daily
rc('font', family='AppleGothic')
plt.rcParams['axes.unicode_minus'] = False
import plotly.graph_objs as go
from plotly import subplots
import plotly.io as po
from stock.analysis.Common import Common
from stock.util.TelegramBot import TelegramBot
class AnalyzerSqlite:
jSDPattern = None
buySell_Daily = None
topCompany = None
fnguide = None
bot = None
common = None
stockFileName = None
analyzedFileName = None
moving_avg = None
def __init__(self, RESOURCE_PATH):
self.common = Common()
self.stockFileName = os.path.join(RESOURCE_PATH, 'stock.db')
self.jSDPattern = JSDPattern_simulation(self.stockFileName)
self.buySell_Daily = BuySell_Daily()
self.stockFileName = self.stockFileName
self.topCompany = self.getTopCompany(self.stockFileName, 2000)
self.fnguide = self.readFnguide(self.stockFileName)
self.bot = TelegramBot()
return
def getTopCompany(self, fnguideFileName, top):
conn = sqlite3.connect(fnguideFileName)
cursor = conn.cursor()
sql = "select DISTINCT CODE, NAME from fnguide order by total_ownership_interest desc limit " + str(top)
cursor.execute(sql)
result = cursor.fetchall()
top_company = {}
for idx, item in enumerate(result):
top_company[item[0]] = (idx+1, item[1])
cursor.close()
conn.close()
return top_company
def readFnguide(self, fnguideFileName):
conn = sqlite3.connect(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 CODE, NAME, ymd, business_profits, business_profits_ratio, debt_ratio, ROA, ROE, EPS, BPS, DPS, PER, PBR FROM fnguide "
sql += " WHERE (ymd=? or ymd=? or ymd=?) and type=''"
sql += " order by code, ymd desc"
cursor.execute(sql, (year1,year2,year3))
result = cursor.fetchall()
fnguide = {}
for item in result:
if item[0] not in fnguide:
fnguide[item[0]] = []
fnguide[item[0]].append(
{'NAME': item[1],
'ymd': item[2],
'business_profits': item[3],
'business_profits_ratio': item[4],
'debt_ratio': item[5],
'ROA': item[6],
'ROE': item[7],
'EPS': item[8],
'BPS': item[9],
'DPS': item[10],
'PER': item[11],
'PBR': item[12]})
cursor.close()
conn.close()
return fnguide
def cz(self, value):
if value is None or math.isnan(value):
return 0
return value
def clear_BSLINE(self, BUY_LIST, sell_type=None):
if sell_type is None or sell_type == '':
BUY_LIST['avg_buy_price'] = 0
BUY_LIST['buy_count'] = 0
BUY_LIST['buy_list'].clear()
else:
BUY_LIST['avg_buy_price'] = 0
BUY_LIST['buy_count'] = 0
tmp_sell_type = sell_type.split(',')
for i, buy_list in reversed(list(enumerate(BUY_LIST['buy_list']))):
for t_sell_type in tmp_sell_type:
if buy_list['buy_type'].strip() == t_sell_type.strip():
del BUY_LIST['buy_list'][i]
break
return
def draw(self, stock_code, data, bsLine=None):
# 어제 데이터는 지운다.
#data = data.loc[pd.DatetimeIndex(data.index).day == int(given_day[6:])]
buy_price_line, buy_count_line, buy_type, buy_count_line, sell_price_line, sell_count_line, sell_type = [], [], [], [], [], [], []
buy_sell_size, buy_colors, sell_colors, buy_colors = [], [], [], []
if bsLine is not None:
buy_price_line = bsLine['buy_price']
buy_count_line = bsLine['buy_count']
sell_price_line = bsLine['sell_price']
sell_count_line = bsLine['sell_count']
buy_type = bsLine['buy_type']
sell_type = bsLine['sell_type']
for i in range(len(data)):
if buy_price_line[i] < 1:
buy_colors.append("#ffffff")
buy_price_line[i] = nan
buy_sell_size.append(0)
else:
buy_colors.append("#0C752E")
buy_sell_size.append(14)
for i in range(len(data)):
if sell_price_line[i] < 1:
sell_colors.append("#ffffff")
sell_price_line[i] = nan
else:
sell_colors.append("#00ced1")
volume_colors = []
for i in range(len(data)):
if data['open'][i] > data['close'][i]:
volume_colors.append("#FF0000")
elif data['open'][i] < data['close'][i]:
volume_colors.append("#FF0000")
else:
volume_colors.append("#000000")
# 그래프를 설정한다.
if bsLine is not None:
buy_text_list, sell_text_list = [], []
for i in range(len(data['ymd'])):
buy_text_list.append(
"{}, {}, {} ({:,.2f})<br><br>"
"avg5: {:.2f}, avg10: {:.2f}, avg20: {:.2f}, avg60: {:.2f}, avg90: {:.2f}, avg120: {:.2f}, avg240: {:.2f}<br>"
"avg360: {:.2f}, avg480: {:.2f}, avg720: {:.2f}, avg1440: {:.2f}, avg2880: {:.2f}<br><br>"
"loc_k: {:.2f}, loc_d: {:.2f}, loc_s: {:.2f}<br><br>"
"laggingSpan_close_diff: {:.4f} ({:.4f})<br>"
"laggingSpan_avg60_diff: {:.4f} ({:.4f})<br>"
"leadingSpan1_leadingSpan2_diff: {:.4f} ({:.4f})<br>"
.format(data['ymd'][i].strftime('%Y-%m-%d %H:%M'), buy_type[i], self.cz(buy_price_line[i]), self.cz(buy_price_line[i])*self.cz(buy_count_line[i]),
self.cz(data["avg5"][i]), self.cz(data["avg10"][i]), self.cz(data["avg20"][i]), self.cz(data["avg60"][i]), self.cz(data["avg90"][i]), self.cz(data["avg120"][i]), self.cz(data["avg240"][i]), self.cz(data["avg360"][i]), self.cz(data["avg480"][i]), self.cz(data["avg720"][i]), self.cz(data["avg1440"][i]), self.cz(data["avg2880"][i]),
self.cz(data['loc_240_k'][i]), self.cz(data['loc_240_d'][i]), self.cz(data['loc_240_s'][i]),
self.cz(data['laggingSpan_close_diff'][i]), self.cz(data['laggingSpan_close_diff_rate'][i]),
self.cz(data['laggingSpan_avg60_diff'][i]), self.cz(data['laggingSpan_avg60_diff_rate'][i]),
self.cz(data['leadingSpan1_leadingSpan2_diff'][i]), self.cz(data['leadingSpan1_leadingSpan2_diff_rate'][i])
))
sell_text_list.append(
"{}, {}, {} ({:,.2f})<br><br>"
"avg5: {:.2f}, avg10: {:.2f}, avg20: {:.2f}, avg60: {:.2f}, avg90: {:.2f}, avg120: {:.2f}, avg240: {:.2f}<br>"
"avg360: {:.2f}, avg480: {:.2f}, avg720: {:.2f}, avg1440: {:.2f}, avg2880: {:.2f}<br><br>"
"loc_k: {:.2f}, loc_d: {:.2f}, loc_s: {:.2f}<br><br>"
"laggingSpan_close_diff: {:.4f} ({:.4f})<br>"
"laggingSpan_avg60_diff: {:.4f} ({:.4f})<br>"
"leadingSpan1_leadingSpan2_diff: {:.4f} ({:.4f})<br>"
.format(
data['ymd'][i].strftime('%Y-%m-%d %H:%M'), sell_type[i], self.cz(sell_price_line[i]), self.cz(sell_price_line[i])*self.cz(sell_count_line[i]),
self.cz(data["avg5"][i]), self.cz(data["avg10"][i]), self.cz(data["avg20"][i]), self.cz(data["avg60"][i]), self.cz(data["avg90"][i]), self.cz(data["avg120"][i]), self.cz(data["avg240"][i]), self.cz(data["avg360"][i]), self.cz(data["avg480"][i]), self.cz(data["avg720"][i]), self.cz(data["avg1440"][i]), self.cz(data["avg2880"][i]),
self.cz(data['loc_240_k'][i]), self.cz(data['loc_240_d'][i]), self.cz(data['loc_240_s'][i]),
self.cz(data['laggingSpan_close_diff'][i]), self.cz(data['laggingSpan_close_diff_rate'][i]),
self.cz(data['laggingSpan_avg60_diff'][i]), self.cz(data['laggingSpan_avg60_diff_rate'][i]),
self.cz(data['leadingSpan1_leadingSpan2_diff'][i]), self.cz(data['leadingSpan1_leadingSpan2_diff_rate'][i])
))
buy_check = go.Scatter(x=data['ymd'], y=buy_price_line, mode='markers', name="buy_price", marker=dict(size=buy_sell_size, color=buy_colors, line_width=0), text=buy_text_list, hoverinfo="text")
sell_check = go.Scatter(x=data['ymd'], y=sell_price_line, mode='markers', name="sell_price", marker=dict(size=14, color=sell_colors, line_width=0), text=sell_text_list, hoverinfo="text")
volume_line = go.Bar(x=data['ymd'], y=data["volume"], marker_color=volume_colors, name='volume')
avg5 = go.Scatter(x=data['ymd'], y=data["avg5"], name="avg5", line_color='#079118')
avg10 = go.Scatter(x=data['ymd'], y=data["avg10"], name="avg10", line_color='grey')
avg20 = go.Scatter(x=data['ymd'], y=data["avg20"], name="avg20", line_color='#d755e8')
avg60 = go.Scatter(x=data['ymd'], y=data["avg60"], name="avg60", line_color='#099B92')
avg90 = go.Scatter(x=data['ymd'], y=data["avg90"], name="avg90", line_color='#2a9c0c')
avg120 = go.Scatter(x=data['ymd'], y=data["avg120"], name="avg120", line_color='#079118')
avg240 = go.Scatter(x=data['ymd'], y=data["avg240"], name="avg240", line_color='#e68456')
avg360 = go.Scatter(x=data['ymd'], y=data["avg360"], name="avg360", line_color='#e6b55c')
avg480 = go.Scatter(x=data['ymd'], y=data["avg480"], name="avg480", line_color='#2a9c0c')
avg720 = go.Scatter(x=data['ymd'], y=data["avg720"], name="avg720", line_color='#e75d53')
avg1440 = go.Scatter(x=data['ymd'], y=data["avg1440"], name="avg1440", line_color='#2a9c0c')
avg2880 = go.Scatter(x=data['ymd'], y=data["avg2880"], name="avg2880", line_color='#46406c')
laggingSpan_0_8_limit = [0.8 for i in data['ymd']]
laggingSpan_0_2_limit = [0.2 for i in data['ymd']]
laggingSpan_0_limit = [0 for i in data['ymd']]
laggingSpan__0_2_limit = [-0.2 for i in data['ymd']]
laggingSpan__0_8_limit = [-0.8 for i in data['ymd']]
laggingSpan_0_8_limit_line = go.Scatter(x=data['ymd'], y=laggingSpan_0_8_limit, line=dict(color='grey', width=1), name='laggingSpan_0_8_limit')
laggingSpan_0_2_limit_line = go.Scatter(x=data['ymd'], y=laggingSpan_0_2_limit, line=dict(color='grey', width=1), name='laggingSpan_0_2_limit')
laggingSpan_0_limit_line = go.Scatter(x=data['ymd'], y=laggingSpan_0_limit, line=dict(color='grey', width=1), name='laggingSpan_0_limit')
laggingSpan__0_2_limit_line = go.Scatter(x=data['ymd'], y=laggingSpan__0_2_limit, line=dict(color='grey', width=1), name='laggingSpan__0_2_limit')
laggingSpan__0_8_limit_line = go.Scatter(x=data['ymd'], y=laggingSpan__0_8_limit, line=dict(color='grey', width=1), name='laggingSpan__0_8_limit')
laggingSpan_close_diff = go.Scatter(x=data['ymd'], y=data["laggingSpan_close_diff"], name="laggingSpan_close_diff", line_color='#079118')
laggingSpan_avg60_diff = go.Scatter(x=data['ymd'], y=data["laggingSpan_avg60_diff"], name="laggingSpan_avg60_diff", line_color='#d755e8')
leadingSpan1_leadingSpan2_diff = go.Scatter(x=data['ymd'], y=data["leadingSpan1_leadingSpan2_diff"], name="leadingSpan1_leadingSpan2_diff", line_color='#d755e8')
laggingSpan_close_diff_rate = go.Scatter(x=data['ymd'], y=data["laggingSpan_close_diff_rate"], name="laggingSpan_close_diff_rate", line_color='#d755e8')
laggingSpan_avg60_diff_rate = go.Scatter(x=data['ymd'], y=data["laggingSpan_avg60_diff_rate"], name="laggingSpan_avg60_diff_rate", line_color='#d755e8')
leadingSpan1_leadingSpan2_diff_rate = go.Scatter(x=data['ymd'], y=data["leadingSpan1_leadingSpan2_diff_rate"], name="leadingSpan1_leadingSpan2_diff_rate", line_color='#d755e8')
changeLine = go.Scatter(x=data['ymd'], y=data["changeLine"], name="changeLine", line_color='#0196ff')
baseLine = go.Scatter(x=data['ymd'], y=data["baseLine"], name="baseLine", line_color='#991515')
laggingSpan = go.Scatter(x=data['ymd'], y=data["laggingSpan"], name="laggingSpan", line_color='#12A524')
leadingSpan1 = go.Scatter(x=data['ymd'], y=data["leadingSpan1"], name="leadingSpan1", line_color='#008001')
leadingSpan2 = go.Scatter(x=data['ymd'], y=data["leadingSpan2"], name="leadingSpan2", line_color='#830fd4')
upper_10_Line = go.Scatter(x=data['ymd'], y=data["upper_10"], name="upper_10", line_color='#0196ff')
lower_10_Line = go.Scatter(x=data['ymd'], y=data["lower_10"], name="lower_10", line_color='#991515')
middle_10_line = go.Scatter(x=data['ymd'], y=data["middle_10"], name="middle_10", line_color='#12A524')
upper_20_Line = go.Scatter(x=data['ymd'], y=data["upper_20"], name="upper_20", line_color='#0196ff')
lower_20_Line = go.Scatter(x=data['ymd'], y=data["lower_20"], name="lower_20", line_color='#991515')
middle_20_line = go.Scatter(x=data['ymd'], y=data["middle_20"], name="middle_20", line_color='#12A524')
loc_240_k = go.Scatter(x=data['ymd'], y=data["loc_240_k"], name="loc_240_k", line_color='#0196ff')
loc_240_d = go.Scatter(x=data['ymd'], y=data["loc_240_d"], name="loc_240_d", line_color='#991515')
loc_240_s = go.Scatter(x=data['ymd'], y=data["loc_240_s"], name="loc_240_s", line_color='#12A524')
new_high_9 = go.Scatter(x=data['ymd'], y=data["new_high_9"], name="new_high_9", line_color='#0196ff')
new_high_26 = go.Scatter(x=data['ymd'], y=data["new_high_26"], name="new_high_26", line_color='#991515')
new_low_9 = go.Scatter(x=data['ymd'], y=data["new_low_9"], name="new_low_9", line_color='#0196ff')
new_low_26 = go.Scatter(x=data['ymd'], y=data["new_low_26"], name="new_low_26", line_color='#991515')
slowk_up_limit = [80 for i in data['ymd']]
slowk_middle_limit = [50 for i in data['ymd']]
slowk_down_limit = [20 for i in data['ymd']]
slowk_up_limit = go.Scatter(x=data['ymd'], y=slowk_up_limit, line=dict(color='grey', width=1), name='slowk_up_limit')
slowk_middle_limit = go.Scatter(x=data['ymd'], y=slowk_middle_limit, line=dict(color='grey', width=1), name='slowk_middle_limit')
slowk_down_limit = go.Scatter(x=data['ymd'], y=slowk_down_limit, line=dict(color='grey', width=1), name='slowk_down_limit')
slowk_12 = go.Scatter(x=data['ymd'], y=data["slowk_12"], line=dict(color='#079118', width=2), name='slowk_12')
slowd_12 = go.Scatter(x=data['ymd'], y=data["slowd_12"], line=dict(dash='dashdot', color='#079118', width=2), name='slowd_12')
slowk_26 = go.Scatter(x=data['ymd'], y=data["slowk_26"], line=dict(color='grey', width=2), name='slowk_26')
slowd_26 = go.Scatter(x=data['ymd'], y=data["slowd_26"], line=dict(dash='dashdot', color='grey', width=2), name='slowd_26')
slowk_52 = go.Scatter(x=data['ymd'], y=data["slowk_52"], line=dict(color='#d755e8', width=2), name='slowk_52')
slowd_52 = go.Scatter(x=data['ymd'], y=data["slowd_52"], line=dict(dash='dashdot', color='#d755e8', width=2), name='slowd_52')
text_list = []
for i in range(len(data['ymd'])):
text_list.append(
"{}<br><br>"
"avg5: {:.2f}, avg10: {:.2f}, avg20: {:.2f}, avg60: {:.2f}, avg90: {:.2f}, avg120: {:.2f}, avg240: {:.2f}<br>"
"avg360: {:.2f}, avg480: {:.2f}, avg720: {:.2f}, avg1440: {:.2f}, avg2880: {:.2f}<br><br>"
"loc_k: {:.2f}, loc_d: {:.2f}, loc_s: {:.2f}<br><br>"
"laggingSpan_close_diff: {:.4f} ({:.4f})<br>"
"laggingSpan_avg60_diff: {:.4f} ({:.4f})<br>"
"leadingSpan1_leadingSpan2_diff: {:.4f} ({:.4f})<br>"
.format(
data['ymd'][i].strftime('%Y-%m-%d %H:%M'),
self.cz(data["avg5"][i]), self.cz(data["avg10"][i]), self.cz(data["avg20"][i]), self.cz(data["avg60"][i]), self.cz(data["avg90"][i]), self.cz(data["avg120"][i]), self.cz(data["avg240"][i]), self.cz(data["avg360"][i]), self.cz(data["avg480"][i]), self.cz(data["avg720"][i]), self.cz(data["avg1440"][i]), self.cz(data["avg2880"][i]),
self.cz(data['loc_240_k'][i]), self.cz(data['loc_240_d'][i]), self.cz(data['loc_240_s'][i]),
self.cz(data['laggingSpan_close_diff'][i]), self.cz(data['laggingSpan_close_diff_rate'][i]),
self.cz(data['laggingSpan_avg60_diff'][i]), self.cz(data['laggingSpan_avg60_diff_rate'][i]),
self.cz(data['leadingSpan1_leadingSpan2_diff'][i]), self.cz(data['leadingSpan1_leadingSpan2_diff_rate'][i])
))
candle_stick = go.Candlestick(x=data['ymd'],
open=data['open'], high=data['high'], low=data['low'], close=data['close'],
increasing_line_color='red', decreasing_line_color='blue',
name='candle', text=text_list, hoverinfo="text"
)
if bsLine is not None:
candle_data = [avg5, avg10, avg20, avg60, avg90, avg120, avg240, avg360, avg480, avg720, avg1440, avg2880, buy_check, sell_check, candle_stick, changeLine, baseLine, laggingSpan, leadingSpan1, leadingSpan2, upper_10_Line, lower_10_Line, middle_10_line, upper_20_Line, lower_20_Line, middle_20_line]
else:
candle_data = [avg5, avg10, avg20, avg60, avg90, avg120, avg240, avg360, avg480, avg720, avg1440, avg2880, candle_stick,changeLine, baseLine, laggingSpan, leadingSpan1, leadingSpan2]
volume_data = [volume_line]
disparity_data = [laggingSpan_close_diff, laggingSpan_avg60_diff, leadingSpan1_leadingSpan2_diff]
loc_disparity_data = [laggingSpan_0_8_limit_line, laggingSpan_0_2_limit_line, laggingSpan_0_limit_line, laggingSpan__0_2_limit_line, laggingSpan__0_8_limit_line,
laggingSpan_close_diff_rate, laggingSpan_avg60_diff_rate, leadingSpan1_leadingSpan2_diff_rate,
loc_240_k, loc_240_d, loc_240_s,
new_high_9 ,new_high_26, new_low_9 ,new_low_26]
stochastic_data = [
slowk_up_limit, slowk_middle_limit, slowk_down_limit,
slowk_12, slowd_12,
slowk_26, slowd_26,
slowk_52, slowd_52
]
# 그래프를 그린다.
"""
fig = go.Figure(data=candle_data)
fig.update_layout(title=stock_code)
fig.show()
"""
fig = subplots.make_subplots(
rows=5, cols=1,
subplot_titles=("이격도", "이격도 위치", "캔들", "slowkd", "거래량"),
shared_xaxes=True, horizontal_spacing=0.03, vertical_spacing=0.01,
row_heights=[200, 200, 700, 200, 200]
)
for trace in disparity_data:
fig.append_trace(trace, 1, 1)
for trace in loc_disparity_data:
fig.append_trace(trace, 2, 1)
for trace in candle_data:
fig.append_trace(trace, 3, 1)
for trace in stochastic_data:
fig.append_trace(trace, 4, 1)
for trace in volume_data:
fig.append_trace(trace, 5, 1)
#fig.update_xaxes(nticks=5)
#fig.update_layout(height=2400, title=stock_code, xaxis_rangeslider_visible=False)
df = pd.DataFrame(bsLine)
df = df.fillna(-1)
buy_count = 0
if bsLine is not None:
buy_count = len(df.loc[df["buy_price"] > 0])
fig.update_layout(height=1400,
title="{}, buy: {}".format(stock_code, buy_count),
xaxis_rangeslider_visible=False,
xaxis2_rangeslider_visible=False,
xaxis3_rangeslider_visible=False,
xaxis4_rangeslider_visible=False
)
# 화면으로 출력함
return fig
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 writeSummary(self, param):
bull = list(param['bull'])
bear = list(param['bear'])
even = list(param['even'])
ymd = [i for i in range(len(bull))]
bull_line = go.Scatter(x=ymd, y=bull, name="bull", line_color='#FF33A2')
bear_line = go.Scatter(x=ymd, y=bear, name="bear", line_color='#1469F4')
even_line = go.Scatter(x=ymd, y=even, name="even", line_color='#8B4513')
line_data = [bull_line, bear_line, even_line]
fig = subplots.make_subplots(
rows=1, cols=1,
subplot_titles=("주식 상황"),
shared_xaxes=True, horizontal_spacing=0.03, vertical_spacing=0.01,
row_heights=[800]
)
for trace in line_data:
fig.append_trace(trace, 1, 1)
fig.update_layout(height=810, xaxis_rangeslider_visible=False)
sum = param['bull'][0] + param['bear'][0] + param['even'][0]
title = "[Summary] bull: %d (%.2f), bear: %d (%.2f), even: %d (%.2f)" % (param['bull'][0], param['bull'][0]/sum, param['bear'][0], param['bear'][0]/sum, param['even'][0], param['even'][0]/sum)
fig['layout'].update(title=title)
#fileName = "%s/summary.html" % (self.outPath)
#po.write_html(fig, file=fileName, auto_open=False)
return
def writeFile(self, outPath, CODE, NAME, top, stock, bsLine):
# 3년 이내 한번이라도 영업이익이 났는지 체크를 함
fnguide = None
if CODE in self.fnguide:
fnguide = self.fnguide[CODE]
check = True
if fnguide:
check = False
for item in fnguide:
if item['business_profits'] > 0:
check = True
if check:
fig = self.draw(CODE, stock, bsLine)
title = "%s (%s), 차트 (<a href=\"https://alphasquare.co.kr/home/stock/financial-information?code=%s\">URL1</a>, <a href=\"https://www.tradingview.com/chart/jJ8zOXz0/?symbol=KRX:%s\">URL2</a>, <a href=\"https://www.investing.com/search/?q=%s\">URL3</a>)" % (NAME, CODE, CODE, CODE, CODE)
fig['layout'].update(title=title)
fileName = outPath + "/%s_%s_%s_%s.html" % (datetime.today().strftime("%Y%m%d"), top, NAME.replace(" ", ""), CODE)
po.write_html(fig, file=fileName, auto_open=False)
return
def checkVolume(self, p_volume, volume):
if 0 < p_volume <= 10000 and p_volume * 700 < volume:
return True
if 10000 < p_volume <= 50000 and p_volume * 40 < volume:
return True
if 50000 < p_volume <= 100000 and p_volume * 25 < volume:
return True
if 100000 < p_volume <= 200000 and p_volume * 15 < volume:
return True
if 200000 < p_volume <= 700000 and p_volume * 13 < volume:
return True
if 700000 < p_volume <= 1000000 and p_volume * 10 < volume:
return True
if 5000000 < p_volume <= 5000000 and p_volume * 5 < volume:
return True
if 5000000 < p_volume and p_volume * 4 < volume:
return True
return False
def getStockData(self, CODE):
data_daily, ci_daily = self.jSDPattern.getData(CODE, ymd=(datetime.now()+timedelta(days=1)).strftime('%Y%m%d'), get_days=1500)
return data_daily, ci_daily
def makeDir(self, dir_name):
if os.path.isdir(self.outPath + "/" + dir_name):
os.rmdir(self.outPath + "/" + dir_name)
os.mkdir(self.outPath + "/" + dir_name)
return
def checkTransaction(self, ticker, data, ci):
# 어제 오늘 데이터로 분석
bsLine = {}
if data is not None and 'close' in data.columns:
size = len(data["close"])
bsLine['buy_ymd'] = [None for i in range(size)]
bsLine['buy_price'] = [0 for i in range(size)]
bsLine['buy_count'] = [0 for i in range(size)]
bsLine['buy_type'] = ['' for i in range(size)]
bsLine['buy_cut'] = [None for i in range(size)]
bsLine['sell_price'] = [0 for i in range(size)]
bsLine['sell_count'] = [0 for i in range(size)]
bsLine['sell_type'] = ['' for i in range(size)]
bsLine['sell_cut'] = [0 for i in range(size)]
size = ci
start = 0
for i in range(start, size):
# 매도 확인
sell_price, sell_count, sell_type = self.buySell_Daily.getSellPrice(ticker, data, i, bsLine)
bsLine['sell_price'][i] = sell_price
bsLine['sell_count'][i] = sell_count
bsLine['sell_type'][i] = sell_type
bsLine['sell_cut'][i] = 0
if sell_price < 1:
buy_ymd, buy_price, buy_count, buy_type, buy_cut = self.buySell_Daily.getBuyPrice(ticker, data, i, bsLine)
bsLine['buy_ymd'][i] = buy_ymd
bsLine['buy_price'][i] = buy_price
bsLine['buy_count'][i] = buy_count
bsLine['buy_type'][i] = buy_type
bsLine['buy_cut'][i] = buy_cut
return bsLine
# 후보 찾기
def findCandidates(self, outPath):
buy_stock_list = []
stockTableName = 'stock'
fnguideTableName = 'fnguide'
conn = sqlite3.connect(self.stockFileName)
cursor = conn.cursor()
cursor.execute('SELECT distinct code, name FROM ' + stockTableName + ' order by code')
#cursor.execute('select CODE, NAME, max(ymd) as ymd from ' + fnguideTableName + ' where type != "E" group by 1 order by total_assets desc')
items = cursor.fetchall()
cursor.close()
conn.close()
for idx, item in enumerate(items):
CODE = item[0]
NAME = item[1]
ticker = {'ticker_code': CODE, 'ticker_name': NAME, 'unit': 0, 'MAX_BUY': 10000, 'BUY_INFO': {'buy_list': []}}
print("#", idx, ", CODE: ", CODE, ", NAME: ", NAME)
stock_daily, ci = self.getStockData(CODE)
bsLine = self.checkTransaction(ticker, stock_daily, ci)
if bsLine['buy_ymd'][ci-1] is not None:
top = "0"
if CODE in self.topCompany:
top = str(self.topCompany[CODE][0])
# 거래량이 10만 이상이고, 종가가 1천원 이상인지 체크 (https://happpy-rich.tistory.com/94)
if stock_daily['volume'][ci-1] > 100000 and stock_daily['close'][ci-1] > 1000:
# 종목 상태 체크 분석
self.writeFile(outPath, CODE, NAME, top, stock_daily, bsLine)
buy_stock_list.append({'CODE': CODE, 'NAME': NAME})
buy_stock_str = ''
for i, item in enumerate(buy_stock_list):
buy_stock_str += str(i + 1) + ". " + item['CODE'] + "(" + item['NAME'] + ")\n"
self.bot.sendMsg("{}".format(buy_stock_str))
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__))))))
RESOURCE_PATH = os.path.join(PROJECT_HOME, 'resources')
analyzerSqlite = AnalyzerSqlite(RESOURCE_PATH)
# HTML 출력
outPath = os.path.join(PROJECT_HOME, "resources", "analysis")
if not os.path.isdir(outPath):
os.mkdir(outPath)
day = datetime.today().strftime("%Y%m%d")
before_7_day = datetime.today() + relativedelta(days=-7)
dayList = os.listdir(outPath)
for dayDir in dayList:
if dayDir[0] != '.' and dayDir < before_7_day.strftime("%Y%m%d"):
if os.path.exists(os.path.join(outPath, dayDir)) and os.path.isdir(os.path.join(outPath, dayDir)):
shutil.rmtree(os.path.join(outPath, dayDir))
outPath = os.path.join(outPath, day)
if os.path.isdir(outPath):
shutil.rmtree(outPath)
os.mkdir(outPath)
print("print to Html...")
analyzerSqlite.findCandidates(outPath)
print("time : %6.2f" % (time.time() - start))
print("done...")

View File

@@ -1,571 +0,0 @@
# https://bibot.tistory.com/63
# https://nonmeyet.tistory.com/entry/Python-TALib%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B9%84%ED%8A%B8%EC%BD%94%EC%9D%B8%EC%A3%BC%EA%B0%80%EA%B8%B0%EC%88%A0%EB%B6%84%EC%84%9D-%EB%B3%B4%EC%A1%B0%EC%A7%80%ED%91%9C-%EC%B6%94%EA%B0%80
# https://lunadaddy.tistory.com/122
# https://wikidocs.net/186885
import os
import numpy as np
np.seterr(divide='ignore', invalid='ignore')
import sqlite3
# https://www.lfd.uci.edu/~gohlke/pythonlibs/#ta-lib
# https://lunadaddy.tistory.com/122
import talib
import pandas as pd
from datetime import datetime, timedelta
from stock.analysis.IchimokuCloud import IchimokuCloud
from sklearn.preprocessing import StandardScaler
class JSDPattern:
stockFileName = None
ichimokuCloud = None
scaler = None
def __init__(self, stockFileName=None):
self.stockFileName = stockFileName
self.ichimokuCloud = IchimokuCloud()
self.scaler = StandardScaler()
return
def makeTickData(self, data, mins=1):
result = {
"ymd": [],
"open": [], "close": [], "high": [], "low": [], "volume": [], "volume_up": [], "volume_down": [], "volume_updown_diff": []
}
for i in range(mins, len(data['ymd'])+1, mins):
result["ymd"].append(data['ymd'][i-1])
result["open"].append(data['open'][i-mins])
result["close"].append(data['close'][i-1])
result["high"].append(max(data['high'][i - mins: i]))
result["low"].append(min(data['low'][i - mins: i]))
result["volume"].append(data['volume'][i-1])
if data['open'][i-1] < data['close'][i-1]:
result["volume_up"].append(data['volume'][i-1])
result["volume_down"].append(0)
elif data['close'][i-1] < data['open'][i-1]:
result["volume_down"].append(-1*data['volume'][i-1])
result["volume_up"].append(0)
else:
result["volume_up"].append(0)
result["volume_down"].append(0)
up = [data['volume'][i - mins + c] for c in range(len(data['volume'][i - mins: i])) if data['close'][i - mins + c] < data['open'][i - mins + c]]
down = [data['volume'][i - mins + c] for c in range(len(data['volume'][i - mins: i])) if data['close'][i - mins + c] < data['open'][i - mins + c]]
result["volume_updown_diff"].append(sum(up) - sum(down))
return result
def append(self, df=None, result=None):
data = {
"ymd": [],
"open": [], "close": [], "high": [], "low": [], "volume": []
}
if result is not None:
for i in range(len(result['ymd'])):
data['ymd'].append(result['ymd'][i])
data['open'].append(result['open'][i])
data['close'].append(result['close'][i])
data['high'].append(result['high'][i])
data['low'].append(result['low'][i])
data['volume'].append(result['volume'][i])
if df is not None:
for i in range(len(df)):
data['ymd'].append(df.index[i])
data['open'].append(df['open'][i])
data['close'].append(df['close'][i])
data['high'].append(df['high'][i])
data['low'].append(df['low'][i])
data['volume'].append(df['volume'][i])
return data
def getDBData(self, stock_code, day, get_days=14):
table = 'stock'
conn = sqlite3.connect(self.stockFileName)
cursor = conn.cursor()
result = {"ymd": [], "open": [], "close": [], "high": [], "low": [], "volume": []}
for i in range(get_days, -1, -1):
this_day = (datetime.strptime(day, '%Y%m%d') - timedelta(i)).strftime('%Y.%m.%d')
cursor.execute('SELECT ymd, open, high, low, close, volume FROM ' + table + ' WHERE CODE=? and ymd=? order by ymd', (stock_code, this_day,))
db_result = cursor.fetchall()
for rows in db_result:
ymd = datetime.strptime(rows[0], '%Y.%m.%d') # hts.날짜
open = rows[1] # hts.시가
high = rows[2] # hts.고가
low = rows[3] # hts.저가
close = rows[4] # hts.종가
vol = rows[5] # hts.거래량
result["ymd"].append(ymd)
result["open"].append(float(open))
result["close"].append(float(close))
result["high"].append(float(high))
result["low"].append(float(low))
result["volume"].append(float(vol))
cursor.close()
conn.close()
return result
def getCoinData(self, ticker, ymd=None, get_days=14):
result = self.getDBData(ticker, ymd, get_days=get_days)
data = self.append(df=None, result=result)
return data
def is_Support(self, low, i, observation_time=5):
# https://sine-qua-none.tistory.com/198
# c1 = df.Low[i] < df.Low[i - 1] < df.Low[i - 2] < df.Low[i - 3]
# c2 = df.Low[i] < df.Low[i + 1] < df.Low[i + 2] < df.Low[i + 3]
# return c1 & c2
#if low[i] == np.min(low[i - 2*self.observation_time:i + 1]):
if low[i] == np.min(low[i - observation_time:i + observation_time + 1]):
return True
else:
return False
def is_Resistance(self, high, i, observation_time=5):
# https://sine-qua-none.tistory.com/198
# c1 = df.High[i] > df.High[i - 1] > df.High[i - 2] > df.High[i - 3]
# c2 = df.High[i] > df.High[i + 1] > df.High[i + 2] > df.High[i + 3]
# return c1 & c2
# if df['high'][i] == np.max(df['high'][i - self.observation_time:i + self.observation_time + 1]):
#if high[i] == np.max(high[i - 2*self.observation_time:i + 1]):
if high[i] == np.max(high[i - observation_time:i + observation_time + 1]):
return True
else:
return False
def getDiff_Rate(self, price1, price2, duration=1440, move=None):
# price1: close, price2: laggingSpan_27
diff = [0 for i in range(len(price1))]
diff_rate = [0 for i in range(len(price1))]
for i in range(0, len(price1)):
if price1[i] is not None and price2[i] is not None:
diff[i] = price1[i] - price2[i]
else:
diff[i] = None
if len(price1) < duration:
duration = 52
for i in range(0, len(price1)):
if duration <= i:
l = [d for d in diff[i - duration:i + 1] if d is not None and 0 < d]
if 0 < len(l):
min_v_p = np.min(l)
else:
min_v_p = 0
l = [d for d in diff[i - duration:i + 1] if d is not None and 0 < d]
if 0 < len(l):
max_v_p = np.max(l)
else:
max_v_p = 0
l = [d for d in diff[i - duration:i + 1] if d is not None and d < 0]
if 0 < len(l):
min_v_m = np.min(l)
else:
min_v_m = 0
l = [d for d in diff[i - duration:i + 1] if d is not None and d < 0]
if 0 < len(l):
max_v_m = np.max(l)
else:
max_v_m = 0
if diff[i] is not None:
if 0 <= diff[i]:
if max_v_p - min_v_p == 0:
diff_rate[i] = 0
else:
diff_rate[i] = (diff[i] - min_v_p) / (max_v_p - min_v_p)
else:
if max_v_m - min_v_m == 0:
diff_rate[i] = 0
else:
diff_rate[i] = ((diff[i] - min_v_m) / (max_v_m - min_v_m)) - 1
else:
diff_rate[i] = None
return diff, diff_rate
def analyze(self, result, mins=1):
result["volume"] = [result["volume"][i] if 0 < result["volume"][i] else 1 for i in range(len(result["volume"]))]
# 기본 캔들 정보
open_df = pd.DataFrame(result["open"])
close_df = pd.DataFrame(result["close"])
high_df = pd.DataFrame(result["high"])
low_df = pd.DataFrame(result["low"])
volume_df = pd.DataFrame(result["volume"])
# 중복 제거
ymd_df = pd.DataFrame(result["ymd"])
data_dup = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1)
data_dup.columns = ["ymd", "open", "close", "high", "low", "volume"]
data_dup.index = pd.DatetimeIndex(result["ymd"])
data_dup_sorted = data_dup.sort_index(ascending=True)
data_dup_sorted = data_dup_sorted.drop_duplicates()
ymd_df = data_dup_sorted["ymd"]
open_df = data_dup_sorted["open"]
close_df = data_dup_sorted["close"]
high_df = data_dup_sorted["high"]
low_df = data_dup_sorted["low"]
volume_df = data_dup_sorted["volume"]
ymd = ymd_df.tolist()
open = open_df.tolist()
close = close_df.tolist()
high = high_df.tolist()
low = low_df.tolist()
volume = volume_df.tolist()
# ichimokuCloud
df = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1)
column_names = ['DATE', 'open', 'close', 'high', 'low', 'volume']
df.columns = column_names
c, b, l, s = 9, 26, 52, 26
# 1. 전환선 = (과거 9일 동안 최고가 + 최저가) / 2
# 당일을 포함한 9일 동안의 최고가와 최저가의 중간 값을 평균으로 나타낸다.
changeLine = (df.high.rolling(c).max() + df.low.rolling(c).min()) / 2
# 2. 기준선 = 과거 26일 동안 최고가 + 최저가) / 2
# 당일을 포함한 26일 동안의 최고가와 최저가의 중간 값을 평균으로 나타낸다.
baseLine = (df.high.rolling(b).max() + df.low.rolling(b).min()) / 2
# 3. 후행스팬 = 현재 close가격의 26일전 반영
laggingSpan = [df.close.values[i + s] for i in range(len(df.close) - s)]
laggingSpan += [None for i in range(s)]
laggingSpan = np.array(laggingSpan)
# 4. 선행스팬 1 = ((기준선 + 전환선) / 2)를 26일 선행하여 배치
# 전환선과 기준선의 평균값을 구해 당일 포함 26일 앞으로 이동시킨 선 (중-단기 구간의 힘을 보여줌)
tmp_leadingSpan1 = (changeLine + baseLine) / 2
""" S: 26일 선행시킴 """
leadingSpan1 = list(tmp_leadingSpan1.values)
for i in range(b - 1):
leadingSpan1.insert(0, None)
""" E: 26일 선행시킴 """
# 5. 선행스팬 2 = ((최근 52일 동안 최고가 + 최저가) / 2)를 26일 선행하여 배치
# 당일을 포함한 52일 동안의 최고가와 최저가의 평균을 26일 앞으로 이동시킨 선 (장기으로 형성된 선이기 때문에 가장 느리게 변함)
tmp_leadingSpan2 = (df.high.rolling(l).max() + df.low.rolling(l).min()) / 2
""" S: 52일 선행시킴 """
leadingSpan2 = list(tmp_leadingSpan2.values)
for i in range(l - 1):
leadingSpan2.insert(0, None)
""" S: 52일 선행시킴 """
baseLine = baseLine.tolist()
changeLine = changeLine.tolist()
laggingSpan = list(laggingSpan)
current_index = len(ymd)
for i in range(51):
if len(ymd) < len(leadingSpan2):
if mins==1440:
ymd.append(ymd[-1] + timedelta(days=1))
else:
ymd.append(ymd[-1] + timedelta(minutes=1))
if len(open) < len(leadingSpan2):
open.append(None)
if len(close) < len(leadingSpan2):
close.append(None)
if len(high) < len(leadingSpan2):
high.append(None)
if len(low) < len(leadingSpan2):
low.append(None)
if len(volume) < len(leadingSpan2):
volume.append(None)
if len(baseLine) < len(leadingSpan2):
baseLine.append(None)
if len(changeLine) < len(leadingSpan2):
changeLine.append(None)
if len(laggingSpan) < len(leadingSpan2):
laggingSpan.append(None)
for i in range(26):
if len(leadingSpan1) < len(leadingSpan2):
leadingSpan1.append(leadingSpan1[-1])
# 9일 신고가
new_high_9 = [0 for c in range(8)] + [1 if (changeLine[c-1] is not None and changeLine[c] is not None and changeLine[c-1] < changeLine[c]) and None not in close[c-8:c+1] and max(close[c-8:c]) < close[c] else 0 for c in range(8, len(close))]
# 26일 신고가
new_high_26 = [0 for c in range(25)] + [1 if (baseLine[c-1] is not None and baseLine[c] is not None and baseLine[c-1] < baseLine[c]) and None not in close[c-8:c+1] and max(close[c-25:c]) < close[c] else 0 for c in range(25, len(close))]
# 33일 신고가
new_high_33 = [0 for c in range(32)] + [1 if (leadingSpan1[c-1] is not None and leadingSpan1[c] is not None and leadingSpan1[c-1] < leadingSpan1[c]) and None not in close[c-8:c+1] and max(close[c-32:c]) < close[c] else 0 for c in range(32, len(close))]
# 52일 신고가
new_high_52 = [0 for c in range(51)] + [1 if (leadingSpan2[c-1] is not None and leadingSpan2[c] is not None and leadingSpan2[c-1] < leadingSpan2[c]) and None not in close[c-8:c+1] and max(close[c-51:c]) < close[c] else 0 for c in range(51, len(close))]
# 9일 신저가
new_low_9 = [0 for c in range(8)] + [1 if (changeLine[c-1] is not None and changeLine[c] is not None and changeLine[c-1] < changeLine[c]) and None not in close[c-8:c+1] and close[c-9] < min(close[c-8:c+1]) else 0 for c in range(8, len(close))]
# 26일 신저가
new_low_26 = [0 for c in range(25)] + [1 if (baseLine[c-1] is not None and baseLine[c] is not None and baseLine[c-1] < baseLine[c]) and None not in close[c-8:c+1] and close[c-26] < min(close[c-25:c+1]) else 0 for c in range(25, len(close))]
# 33일 신저가
new_low_33 = [0 for c in range(32)] + [1 if (leadingSpan1[c-1] is not None and leadingSpan1[c] is not None and leadingSpan1[c-1] < leadingSpan1[c]) and None not in close[c-8:c+1] and close[c-33] < min(close[c-32:c+1]) else 0 for c in range(32, len(close))]
# 52일 신저가
new_low_52 = [0 for c in range(51)] + [1 if (leadingSpan2[c-1] is not None and leadingSpan2[c] is not None and leadingSpan2[c-1] < leadingSpan2[c]) and None not in close[c-8:c+1] and close[c-52] < min(close[c-51:c+1]) else 0 for c in range(51, len(close))]
# 이동 평균
close_df = pd.DataFrame(close)
avg5 = list(np.reshape(close_df.ewm(5).mean().values, -1))
avg10 = list(np.reshape(close_df.ewm(10).mean().values, -1))
avg20 = list(np.reshape(close_df.ewm(20).mean().values, -1))
avg60 = list(np.reshape(close_df.ewm(60).mean().values, -1))
avg90 = list(np.reshape(close_df.ewm(90).mean().values, -1))
avg120 = list(np.reshape(close_df.ewm(120).mean().values, -1))
avg240 = list(np.reshape(close_df.ewm(240).mean().values, -1))
avg360 = list(np.reshape(close_df.ewm(360).mean().values, -1))
avg480 = list(np.reshape(close_df.ewm(480).mean().values, -1))
avg720 = list(np.reshape(close_df.ewm(720).mean().values, -1))
avg1440 = list(np.reshape(close_df.ewm(1440).mean().values, -1))
avg2880 = list(np.reshape(close_df.ewm(2880).mean().values, -1))
np_high, np_low, np_close = np.array(high, dtype=np.float64), np.array(low, dtype=np.float64), np.array(close, dtype=np.float64)
slowk_12_df, slowd_12_df = talib.STOCH(np_high, np_low, np_close, fastk_period=12, slowk_period=5, slowk_matype=0, slowd_period=5, slowd_matype=0)
slowk_26_df, slowd_26_df = talib.STOCH(np_high, np_low, np_close, fastk_period=26, slowk_period=16, slowk_matype=0, slowd_period=16, slowd_matype=0)
slowk_52_df, slowd_52_df = talib.STOCH(np_high, np_low, np_close, fastk_period=52, slowk_period=32, slowk_matype=0, slowd_period=32, slowd_matype=0)
# 최고/최저 위치
loc_240 = [None for i in range(len(close))]
for i in range(240, len(close)):
min_v = np.min(result["close"][i-239:i+1])
max_v = np.max(result["close"][i-239:i+1])
if close[i] is not None:
loc_240[i] = ((close[i] - min_v) / (max_v - min_v))
else:
loc_240[i] = None
loc_240 = pd.DataFrame(loc_240)
loc_240_k = loc_240.to_numpy().reshape(-1)
loc_240_d = loc_240.rolling(20).mean()
loc_240_s = loc_240.rolling(60).mean()
loc_240_d = loc_240_d.to_numpy().reshape(-1)
loc_240_s = loc_240_s.to_numpy().reshape(-1)
# 볼린저 밴드
n, t = 10, 2
max_10 = close_df.rolling(window=n).mean()
stddev_10 = close_df.rolling(window=n).std()
upper_10 = max_10 + (stddev_10 * t) # 상단 볼리저 밴드
lower_10 = max_10 - (stddev_10 * t) # 하단 볼리저 밴드
middle_10 = (upper_10 + lower_10) / 2
upper_10 = list(np.reshape(upper_10.values, -1))
lower_10 = list(np.reshape(lower_10.values, -1))
middle_10 = list(np.reshape(middle_10.values, -1))
n, t = 20, 2
max_20 = close_df.rolling(window=n).mean()
stddev_20 = close_df.rolling(window=n).std()
upper_20 = max_20 + (stddev_20 * t) # 상단 볼리저 밴드
lower_20 = max_20 - (stddev_20 * t) # 하단 볼리저 밴드
middle_20 = (upper_20 + lower_20) / 2
upper_20 = list(np.reshape(upper_20.values, -1))
lower_20 = list(np.reshape(lower_20.values, -1))
middle_20 = list(np.reshape(middle_20.values, -1))
duration = 1440
if mins == 1440:
duration = 360
laggingSpan_close_diff, laggingSpan_close_diff_rate = self.getDiff_Rate(laggingSpan, close, duration=duration)
laggingSpan_changeLine_diff, laggingSpan_changeLine_diff_rate = self.getDiff_Rate(laggingSpan, changeLine, duration=duration)
laggingSpan_baseLine_diff, laggingSpan_baseLine_diff_rate = self.getDiff_Rate(laggingSpan, baseLine, duration=duration)
laggingSpan_leadingSpan1_diff, laggingSpan_leadingSpan1_diff_rate = self.getDiff_Rate(laggingSpan, leadingSpan1, duration=duration)
laggingSpan_leadingSpan2_diff, laggingSpan_leadingSpan2_diff_rate = self.getDiff_Rate(laggingSpan, leadingSpan2, duration=duration)
laggingSpan_avg60_diff, laggingSpan_avg60_diff_rate = self.getDiff_Rate(laggingSpan, avg60, duration=duration)
laggingSpan_lower10_diff, laggingSpan_lower10_diff_rate = self.getDiff_Rate(laggingSpan, lower_10, duration=duration)
laggingSpan_middle10_diff, laggingSpan_middle10_diff_rate = self.getDiff_Rate(laggingSpan, middle_10, duration=duration)
laggingSpan_upper10_diff, laggingSpan_upper10_diff_rate = self.getDiff_Rate(laggingSpan, upper_10, duration=duration)
laggingSpan_lower20_diff, laggingSpan_lower20_diff_rate = self.getDiff_Rate(laggingSpan, lower_20, duration=duration)
laggingSpan_middle20_diff, laggingSpan_middle20_diff_rate = self.getDiff_Rate(laggingSpan, middle_20, duration=duration)
laggingSpan_upper20_diff, laggingSpan_upper20_diff_rate = self.getDiff_Rate(laggingSpan, upper_20, duration=duration)
baseLine_close_diff, baseLine_close_diff_rate = self.getDiff_Rate(baseLine, close, duration=duration)
changeLine_close_diff, changeLine_close_diff_rate = self.getDiff_Rate(changeLine, close, duration=duration)
changeLine_baseLine_diff, changeLine_baseLine_diff_rate = self.getDiff_Rate(changeLine, baseLine, duration=duration)
changeLine_leadingSpan1_diff, changeLine_leadingSpan1_diff_rate = self.getDiff_Rate(changeLine, leadingSpan1, duration=duration)
leadingSpan1_leadingSpan2_diff, leadingSpan1_leadingSpan2_diff_rate = self.getDiff_Rate(leadingSpan1, leadingSpan2, duration=duration)
df_list = [
pd.DataFrame(ymd),
pd.DataFrame(open), pd.DataFrame(close), pd.DataFrame(high), pd.DataFrame(low), pd.DataFrame(volume),
pd.DataFrame(changeLine), pd.DataFrame(baseLine), pd.DataFrame(laggingSpan), pd.DataFrame(leadingSpan1), pd.DataFrame(leadingSpan2),
pd.DataFrame(laggingSpan_close_diff),
pd.DataFrame(laggingSpan_changeLine_diff),
pd.DataFrame(laggingSpan_baseLine_diff),
pd.DataFrame(laggingSpan_leadingSpan1_diff),
pd.DataFrame(laggingSpan_leadingSpan2_diff),
pd.DataFrame(laggingSpan_avg60_diff),
pd.DataFrame(laggingSpan_lower10_diff),
pd.DataFrame(laggingSpan_middle10_diff),
pd.DataFrame(laggingSpan_upper10_diff),
pd.DataFrame(laggingSpan_lower20_diff),
pd.DataFrame(laggingSpan_middle20_diff),
pd.DataFrame(laggingSpan_upper20_diff),
pd.DataFrame(baseLine_close_diff),
pd.DataFrame(changeLine_close_diff),
pd.DataFrame(changeLine_baseLine_diff),
pd.DataFrame(changeLine_leadingSpan1_diff),
pd.DataFrame(leadingSpan1_leadingSpan2_diff),
pd.DataFrame(laggingSpan_close_diff_rate),
pd.DataFrame(laggingSpan_changeLine_diff_rate),
pd.DataFrame(laggingSpan_baseLine_diff_rate),
pd.DataFrame(laggingSpan_leadingSpan1_diff_rate),
pd.DataFrame(laggingSpan_leadingSpan2_diff_rate),
pd.DataFrame(laggingSpan_avg60_diff_rate),
pd.DataFrame(laggingSpan_lower10_diff_rate),
pd.DataFrame(laggingSpan_middle10_diff_rate),
pd.DataFrame(laggingSpan_upper10_diff_rate),
pd.DataFrame(laggingSpan_lower20_diff_rate),
pd.DataFrame(laggingSpan_middle20_diff_rate),
pd.DataFrame(laggingSpan_upper20_diff_rate),
pd.DataFrame(baseLine_close_diff_rate),
pd.DataFrame(changeLine_close_diff_rate),
pd.DataFrame(changeLine_baseLine_diff_rate),
pd.DataFrame(changeLine_leadingSpan1_diff_rate),
pd.DataFrame(leadingSpan1_leadingSpan2_diff_rate),
pd.DataFrame(loc_240_k), pd.DataFrame(loc_240_d), pd.DataFrame(loc_240_s),
pd.DataFrame(avg5), pd.DataFrame(avg10), pd.DataFrame(avg20), pd.DataFrame(avg60), pd.DataFrame(avg90), pd.DataFrame(avg120), pd.DataFrame(avg240), pd.DataFrame(avg360), pd.DataFrame(avg480), pd.DataFrame(avg720), pd.DataFrame(avg1440), pd.DataFrame(avg2880),
pd.DataFrame(upper_10), pd.DataFrame(lower_10), pd.DataFrame(middle_10),
pd.DataFrame(upper_20), pd.DataFrame(lower_20), pd.DataFrame(middle_20),
pd.DataFrame(new_high_9), pd.DataFrame(new_high_26), pd.DataFrame(new_high_33), pd.DataFrame(new_high_52),
pd.DataFrame(new_low_9), pd.DataFrame(new_low_26), pd.DataFrame(new_low_33), pd.DataFrame(new_low_52),
pd.DataFrame(slowk_12_df), pd.DataFrame(slowd_12_df),
pd.DataFrame(slowk_26_df), pd.DataFrame(slowd_26_df),
pd.DataFrame(slowk_52_df), pd.DataFrame(slowd_52_df),
]
data = pd.concat(df_list, axis=1)
column_names = [
'ymd',
'open', 'close', 'high', 'low', 'volume',
'changeLine', 'baseLine', 'laggingSpan', 'leadingSpan1', 'leadingSpan2',
'laggingSpan_close_diff',
'laggingSpan_changeLine_diff',
'laggingSpan_baseLine_diff',
'laggingSpan_leadingSpan1_diff',
'laggingSpan_leadingSpan2_diff',
'laggingSpan_avg60_diff',
'laggingSpan_lower10_diff',
'laggingSpan_middle10_diff',
'laggingSpan_upper10_diff',
'laggingSpan_lower20_diff',
'laggingSpan_middle20_diff',
'laggingSpan_upper20_diff',
'baseLine_close_diff',
'changeLine_close_diff',
'changeLine_baseLine_diff',
'changeLine_leadingSpan1_diff',
'leadingSpan1_leadingSpan2_diff',
'laggingSpan_close_diff_rate',
'laggingSpan_changeLine_diff_rate',
'laggingSpan_baseLine_diff_rate',
'laggingSpan_leadingSpan1_diff_rate',
'laggingSpan_leadingSpan2_diff_rate',
'laggingSpan_avg60_diff_rate',
'laggingSpan_lower10_diff_rate',
'laggingSpan_middle10_diff_rate',
'laggingSpan_upper10_diff_rate',
'laggingSpan_lower20_diff_rate',
'laggingSpan_middle20_diff_rate',
'laggingSpan_upper20_diff_rate',
'baseLine_close_diff_rate',
'changeLine_close_diff_rate',
'changeLine_baseLine_diff_rate',
'changeLine_leadingSpan1_diff_rate',
'leadingSpan1_leadingSpan2_diff_rate',
'loc_240_k', 'loc_240_d', 'loc_240_s',
'avg5', 'avg10', 'avg20', 'avg60', 'avg90', 'avg120', 'avg240', 'avg360', 'avg480', 'avg720', 'avg1440', 'avg2880',
'upper_10', 'lower_10', 'middle_10',
'upper_20', 'lower_20', 'middle_20',
'new_high_9', 'new_high_26', 'new_high_33', 'new_high_52',
'new_low_9', 'new_low_26', 'new_low_33', 'new_low_52',
'slowk_12', 'slowd_12',
'slowk_26', 'slowd_26',
'slowk_52', 'slowd_52',
]
data.columns = column_names
data.index = pd.DatetimeIndex(ymd)
return data, current_index
def getData(self, ticker, mins=None, ymd=None, get_days=14):
if ymd is None:
result = self.getCoinData(ticker, mins=mins, get_days=get_days)
else:
result = self.getCoinData(ticker, mins=mins, ymd=ymd, get_days=get_days)
if len(result['ymd']) < 1:
return None, None
#result_tic = self.makeTickData(result_m1, mins=minute)
data, current_index = self.analyze(result, mins=mins)
return data, current_index
def analyzePattern(self, data):
# jSDPattern.analyzePattern(data)
data = data[['open', 'high', 'low', 'close', 'volume']].astype(float)
pattern_names = talib.get_function_groups()['Pattern Recognition']
pattern_results = {}
for pattern in pattern_names:
pattern_function = getattr(talib, pattern)
result = pattern_function(data['open'].values, data['high'].values, data['low'].values, data['close'].values)
if result[-1] != 0:
pattern_results[pattern] = result[-1]
if len(pattern_results) > 0:
for pattern, result in pattern_results.items():
if result > 0:
direction = "상승"
else:
direction = "하락"
print(f"{pattern}: {direction}")
else:
print("인식된 차트 패턴이 없습니다.")
return
if __name__ == "__main__":
def min_max_normalize(data):
min_val = min(data)
max_val = max(data)
normalized_data = [(x - min_val) / (max_val - min_val) for x in data]
return normalized_data
# 예시 데이터
original_data = [-4, -3, -2, -1, 0]
normalized_data = min_max_normalize(original_data)
print(np.asarray(normalized_data)-1)
original_data = [0, 2,4,6,8,10]
normalized_data = min_max_normalize(original_data)
print(normalized_data)

View File

@@ -1,255 +0,0 @@
# https://bibot.tistory.com/63
# https://nonmeyet.tistory.com/entry/Python-TALib%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B9%84%ED%8A%B8%EC%BD%94%EC%9D%B8%EC%A3%BC%EA%B0%80%EA%B8%B0%EC%88%A0%EB%B6%84%EC%84%9D-%EB%B3%B4%EC%A1%B0%EC%A7%80%ED%91%9C-%EC%B6%94%EA%B0%80
# https://lunadaddy.tistory.com/122
# https://wikidocs.net/186885
import os
from scipy.signal import savgol_filter
import numpy as np
np.seterr(divide='ignore', invalid='ignore')
# https://www.lfd.uci.edu/~gohlke/pythonlibs/#ta-lib
# https://lunadaddy.tistory.com/122
import talib
import pandas as pd
from datetime import datetime, timedelta
from stock.analysis.JSDPattern import JSDPattern
class JSDPattern_realtime (JSDPattern):
def __init__(self, stockFileName=None):
super().__init__(stockFileName)
return
def analyze(self, result):
result["volume"] = [result["volume"][i] if 0 < result["volume"][i] else 1 for i in range(len(result["volume"]))]
# 기본 캔들 정보
open_df = pd.DataFrame(result["open"])
close_df = pd.DataFrame(result["close"])
high_df = pd.DataFrame(result["high"])
low_df = pd.DataFrame(result["low"])
volume_df = pd.DataFrame(result["volume"])
# 중복 제거
ymd_df = pd.DataFrame(result["ymd"])
data_dup = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1)
data_dup.columns = ["ymd", "open", "close", "high", "low", "volume"]
data_dup.index = pd.DatetimeIndex(result["ymd"])
data_dup_sorted = data_dup.sort_index(ascending=True)
data_dup_sorted = data_dup_sorted.drop_duplicates()
ymd_df = data_dup_sorted["ymd"]
open_df = data_dup_sorted["open"]
close_df = data_dup_sorted["close"]
high_df = data_dup_sorted["high"]
low_df = data_dup_sorted["low"]
volume_df = data_dup_sorted["volume"]
ymd = ymd_df.tolist()
open = open_df.tolist()
close = close_df.tolist()
high = high_df.tolist()
low = low_df.tolist()
volume = volume_df.tolist()
# ichimokuCloud
df = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1)
column_names = ['DATE', 'open', 'close', 'high', 'low', 'volume']
df.columns = column_names
c, b, l, s = 9, 26, 52, 26
# 1. 전환선 = (과거 9일 동안 최고가 + 최저가) / 2
# 당일을 포함한 9일 동안의 최고가와 최저가의 중간 값을 평균으로 나타낸다.
changeLine = (df.high.rolling(c).max() + df.low.rolling(c).min()) / 2
# 2. 기준선 = 과거 26일 동안 최고가 + 최저가) / 2
# 당일을 포함한 26일 동안의 최고가와 최저가의 중간 값을 평균으로 나타낸다.
baseLine = (df.high.rolling(b).max() + df.low.rolling(b).min()) / 2
# 3. 후행스팬 = 현재 close가격의 26일전 반영
laggingSpan = [df.close.values[i + s] for i in range(len(df.close) - s)]
laggingSpan += [None for i in range(s)]
laggingSpan = np.array(laggingSpan)
# 4. 선행스팬 1 = ((기준선 + 전환선) / 2)를 26일 선행하여 배치
# 전환선과 기준선의 평균값을 구해 당일 포함 26일 앞으로 이동시킨 선 (중-단기 구간의 힘을 보여줌)
tmp_leadingSpan1 = (changeLine + baseLine) / 2
""" S: 26일 선행시킴 """
leadingSpan1 = list(tmp_leadingSpan1.values)
for i in range(b - 1):
leadingSpan1.insert(0, None)
""" E: 26일 선행시킴 """
# 5. 선행스팬 2 = ((최근 52일 동안 최고가 + 최저가) / 2)를 26일 선행하여 배치
# 당일을 포함한 52일 동안의 최고가와 최저가의 평균을 26일 앞으로 이동시킨 선 (장기으로 형성된 선이기 때문에 가장 느리게 변함)
tmp_leadingSpan2 = (df.high.rolling(l).max() + df.low.rolling(l).min()) / 2
""" S: 52일 선행시킴 """
leadingSpan2 = list(tmp_leadingSpan2.values)
for i in range(l - 1):
leadingSpan2.insert(0, None)
""" S: 52일 선행시킴 """
baseLine = baseLine.tolist()
changeLine = changeLine.tolist()
laggingSpan = list(laggingSpan)
current_index = len(ymd)
for i in range(51):
if len(ymd) < len(leadingSpan2):
ymd.append(ymd[-1] + timedelta(days=1))
if len(open) < len(leadingSpan2):
open.append(None)
if len(close) < len(leadingSpan2):
close.append(None)
if len(high) < len(leadingSpan2):
high.append(None)
if len(low) < len(leadingSpan2):
low.append(None)
if len(volume) < len(leadingSpan2):
volume.append(None)
if len(baseLine) < len(leadingSpan2):
baseLine.append(None)
if len(changeLine) < len(leadingSpan2):
changeLine.append(None)
if len(laggingSpan) < len(leadingSpan2):
laggingSpan.append(None)
for i in range(26):
if len(leadingSpan1) < len(leadingSpan2):
leadingSpan1.append(leadingSpan1[-1])
# 9일 신고가
new_high_9 = [0 for c in range(8)] + [1 if (changeLine[c-1] is not None and changeLine[c] is not None and changeLine[c-1] < changeLine[c]) and None not in close[c-8:c+1] and max(close[c-8:c]) < close[c] else 0 for c in range(8, len(close))]
# 26일 신고가
new_high_26 = [0 for c in range(25)] + [1 if (baseLine[c-1] is not None and baseLine[c] is not None and baseLine[c-1] < baseLine[c]) and None not in close[c-8:c+1] and max(close[c-25:c]) < close[c] else 0 for c in range(25, len(close))]
# 9일 신저가
new_low_9 = [0 for c in range(8)] + [1 if (changeLine[c-1] is not None and changeLine[c] is not None and changeLine[c-1] < changeLine[c]) and None not in close[c-8:c+1] and close[c-9] < min(close[c-8:c+1]) else 0 for c in range(8, len(close))]
# 26일 신저가
new_low_26 = [0 for c in range(25)] + [1 if (baseLine[c-1] is not None and baseLine[c] is not None and baseLine[c-1] < baseLine[c]) and None not in close[c-8:c+1] and close[c-26] < min(close[c-25:c+1]) else 0 for c in range(25, len(close))]
# 이동 평균
close_df = pd.DataFrame(close)
avg5 = list(np.reshape(close_df.ewm(5).mean().values, -1))
avg10 = list(np.reshape(close_df.ewm(10).mean().values, -1))
avg20 = list(np.reshape(close_df.ewm(20).mean().values, -1))
avg60 = list(np.reshape(close_df.ewm(60).mean().values, -1))
avg90 = list(np.reshape(close_df.ewm(90).mean().values, -1))
avg120 = list(np.reshape(close_df.ewm(120).mean().values, -1))
avg240 = list(np.reshape(close_df.ewm(240).mean().values, -1))
avg360 = list(np.reshape(close_df.ewm(360).mean().values, -1))
avg480 = list(np.reshape(close_df.ewm(480).mean().values, -1))
np_high, np_low, np_close = np.array(high, dtype=np.float64), np.array(low, dtype=np.float64), np.array(close, dtype=np.float64)
slowk_12_df, slowd_12_df = talib.STOCH(np_high, np_low, np_close, fastk_period=12, slowk_period=5, slowk_matype=0, slowd_period=5, slowd_matype=0)
slowk_26_df, slowd_26_df = talib.STOCH(np_high, np_low, np_close, fastk_period=26, slowk_period=16, slowk_matype=0, slowd_period=16, slowd_matype=0)
slowk_52_df, slowd_52_df = talib.STOCH(np_high, np_low, np_close, fastk_period=52, slowk_period=32, slowk_matype=0, slowd_period=32, slowd_matype=0)
# 볼린저 밴드
n, t = 10, 2
max_10 = close_df.rolling(window=n).mean()
stddev_10 = close_df.rolling(window=n).std()
upper_10 = max_10 + (stddev_10 * t) # 상단 볼리저 밴드
lower_10 = max_10 - (stddev_10 * t) # 하단 볼리저 밴드
middle_10 = (upper_10 + lower_10) / 2
upper_10 = list(np.reshape(upper_10.values, -1))
lower_10 = list(np.reshape(lower_10.values, -1))
middle_10 = list(np.reshape(middle_10.values, -1))
n, t = 20, 2
max_20 = close_df.rolling(window=n).mean()
stddev_20 = close_df.rolling(window=n).std()
upper_20 = max_20 + (stddev_20 * t) # 상단 볼리저 밴드
lower_20 = max_20 - (stddev_20 * t) # 하단 볼리저 밴드
middle_20 = (upper_20 + lower_20) / 2
upper_20 = list(np.reshape(upper_20.values, -1))
lower_20 = list(np.reshape(lower_20.values, -1))
middle_20 = list(np.reshape(middle_20.values, -1))
duration = 360
laggingSpan_close_diff, laggingSpan_close_diff_rate = self.getDiff_Rate(laggingSpan, close, duration=duration)
laggingSpan_avg60_diff, laggingSpan_avg60_diff_rate = self.getDiff_Rate(laggingSpan, avg60, duration=duration)
leadingSpan1_leadingSpan2_diff, leadingSpan1_leadingSpan2_diff_rate = self.getDiff_Rate(leadingSpan1, leadingSpan2, duration=duration)
df_list = [
pd.DataFrame(ymd),
pd.DataFrame(open), pd.DataFrame(close), pd.DataFrame(high), pd.DataFrame(low), pd.DataFrame(volume),
pd.DataFrame(changeLine), pd.DataFrame(baseLine), pd.DataFrame(laggingSpan), pd.DataFrame(leadingSpan1), pd.DataFrame(leadingSpan2),
pd.DataFrame(laggingSpan_close_diff),
pd.DataFrame(laggingSpan_avg60_diff),
pd.DataFrame(leadingSpan1_leadingSpan2_diff),
pd.DataFrame(laggingSpan_close_diff_rate),
pd.DataFrame(laggingSpan_avg60_diff_rate),
pd.DataFrame(leadingSpan1_leadingSpan2_diff_rate),
pd.DataFrame(avg5), pd.DataFrame(avg10), pd.DataFrame(avg20), pd.DataFrame(avg60), pd.DataFrame(avg90), pd.DataFrame(avg120), pd.DataFrame(avg240), pd.DataFrame(avg360), pd.DataFrame(avg480),
pd.DataFrame(upper_10), pd.DataFrame(lower_10), pd.DataFrame(middle_10),
pd.DataFrame(upper_20), pd.DataFrame(lower_20), pd.DataFrame(middle_20),
pd.DataFrame(new_high_9), pd.DataFrame(new_high_26),
pd.DataFrame(new_low_9), pd.DataFrame(new_low_26),
pd.DataFrame(slowk_12_df), pd.DataFrame(slowd_12_df),
pd.DataFrame(slowk_26_df), pd.DataFrame(slowd_26_df),
pd.DataFrame(slowk_52_df), pd.DataFrame(slowd_52_df),
]
data = pd.concat(df_list, axis=1)
column_names = [
'ymd',
'open', 'close', 'high', 'low', 'volume',
'changeLine', 'baseLine', 'laggingSpan', 'leadingSpan1', 'leadingSpan2',
'laggingSpan_close_diff',
'laggingSpan_avg60_diff',
'leadingSpan1_leadingSpan2_diff',
'laggingSpan_close_diff_rate',
'laggingSpan_avg60_diff_rate',
'leadingSpan1_leadingSpan2_diff_rate',
'avg5', 'avg10', 'avg20', 'avg60', 'avg90', 'avg120', 'avg240', 'avg360', 'avg480',
'upper_10', 'lower_10', 'middle_10',
'upper_20', 'lower_20', 'middle_20',
'new_high_9', 'new_high_26',
'new_low_9', 'new_low_26',
'slowk_12', 'slowd_12',
'slowk_26', 'slowd_26',
'slowk_52', 'slowd_52',
]
data.columns = column_names
data.index = pd.DatetimeIndex(ymd)
return data, current_index
def getData(self, ticker, ymd=None, get_days=14):
if ymd is None:
result = self.getCoinData(ticker, get_days=get_days)
else:
result = self.getCoinData(ticker, ymd=ymd, get_days=get_days)
if len(result['ymd']) < 1:
return None, None
#result_tic = self.makeTickData(result_m1, mins=minute)
data, current_index = self.analyze(result)
return data, current_index
if __name__ == "__main__":
def min_max_normalize(data):
min_val = min(data)
max_val = max(data)
normalized_data = [(x - min_val) / (max_val - min_val) for x in data]
return normalized_data
# 예시 데이터
original_data = [-4, -3, -2, -1, 0]
normalized_data = min_max_normalize(original_data)
print(np.asarray(normalized_data)-1)
original_data = [0, 2,4,6,8,10]
normalized_data = min_max_normalize(original_data)
print(normalized_data)

View File

@@ -1,288 +0,0 @@
# https://bibot.tistory.com/63
# https://nonmeyet.tistory.com/entry/Python-TALib%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B9%84%ED%8A%B8%EC%BD%94%EC%9D%B8%EC%A3%BC%EA%B0%80%EA%B8%B0%EC%88%A0%EB%B6%84%EC%84%9D-%EB%B3%B4%EC%A1%B0%EC%A7%80%ED%91%9C-%EC%B6%94%EA%B0%80
# https://lunadaddy.tistory.com/122
# https://wikidocs.net/186885
import os
from scipy.signal import savgol_filter
import numpy as np
np.seterr(divide='ignore', invalid='ignore')
# https://www.lfd.uci.edu/~gohlke/pythonlibs/#ta-lib
# https://lunadaddy.tistory.com/122
import talib
import pandas as pd
from datetime import datetime, timedelta
from stock.analysis.IchimokuCloud import IchimokuCloud
from sklearn.preprocessing import StandardScaler
from stock.analysis.JSDPattern import JSDPattern
class JSDPattern_simulation (JSDPattern):
def __init__(self, RESOURCE_PATH=None):
super().__init__(RESOURCE_PATH)
return
def analyze(self, result, mins=1440):
result["volume"] = [result["volume"][i] if 0 < result["volume"][i] else 1 for i in range(len(result["volume"]))]
# 기본 캔들 정보
open_df = pd.DataFrame(result["open"])
close_df = pd.DataFrame(result["close"])
high_df = pd.DataFrame(result["high"])
low_df = pd.DataFrame(result["low"])
volume_df = pd.DataFrame(result["volume"])
# 중복 제거
ymd_df = pd.DataFrame(result["ymd"])
data_dup = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1)
data_dup.columns = ["ymd", "open", "close", "high", "low", "volume"]
data_dup.index = pd.DatetimeIndex(result["ymd"])
data_dup_sorted = data_dup.sort_index(ascending=True)
data_dup_sorted = data_dup_sorted.drop_duplicates()
ymd_df = data_dup_sorted["ymd"]
open_df = data_dup_sorted["open"]
close_df = data_dup_sorted["close"]
high_df = data_dup_sorted["high"]
low_df = data_dup_sorted["low"]
volume_df = data_dup_sorted["volume"]
ymd = ymd_df.tolist()
open = open_df.tolist()
close = close_df.tolist()
high = high_df.tolist()
low = low_df.tolist()
volume = volume_df.tolist()
# ichimokuCloud
df = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1)
column_names = ['DATE', 'open', 'close', 'high', 'low', 'volume']
df.columns = column_names
c, b, l, s = 9, 26, 52, 26
# 1. 전환선 = (과거 9일 동안 최고가 + 최저가) / 2
# 당일을 포함한 9일 동안의 최고가와 최저가의 중간 값을 평균으로 나타낸다.
changeLine = (df.high.rolling(c).max() + df.low.rolling(c).min()) / 2
# 2. 기준선 = 과거 26일 동안 최고가 + 최저가) / 2
# 당일을 포함한 26일 동안의 최고가와 최저가의 중간 값을 평균으로 나타낸다.
baseLine = (df.high.rolling(b).max() + df.low.rolling(b).min()) / 2
# 3. 후행스팬 = 현재 close가격의 26일전 반영
laggingSpan = [df.close.values[i + s] for i in range(len(df.close) - s)]
laggingSpan += [None for i in range(s)]
laggingSpan = np.array(laggingSpan)
# 4. 선행스팬 1 = ((기준선 + 전환선) / 2)를 26일 선행하여 배치
# 전환선과 기준선의 평균값을 구해 당일 포함 26일 앞으로 이동시킨 선 (중-단기 구간의 힘을 보여줌)
tmp_leadingSpan1 = (changeLine + baseLine) / 2
""" S: 26일 선행시킴 """
leadingSpan1 = list(tmp_leadingSpan1.values)
for i in range(b - 1):
leadingSpan1.insert(0, None)
""" E: 26일 선행시킴 """
# 5. 선행스팬 2 = ((최근 52일 동안 최고가 + 최저가) / 2)를 26일 선행하여 배치
# 당일을 포함한 52일 동안의 최고가와 최저가의 평균을 26일 앞으로 이동시킨 선 (장기으로 형성된 선이기 때문에 가장 느리게 변함)
tmp_leadingSpan2 = (df.high.rolling(l).max() + df.low.rolling(l).min()) / 2
""" S: 52일 선행시킴 """
leadingSpan2 = list(tmp_leadingSpan2.values)
for i in range(l - 1):
leadingSpan2.insert(0, None)
""" S: 52일 선행시킴 """
baseLine = baseLine.tolist()
changeLine = changeLine.tolist()
laggingSpan = list(laggingSpan)
current_index = len(ymd)
for i in range(51):
if len(ymd) < len(leadingSpan2):
if mins==1440:
ymd.append(ymd[-1] + timedelta(days=1))
else:
ymd.append(ymd[-1] + timedelta(minutes=1))
if len(open) < len(leadingSpan2):
open.append(None)
if len(close) < len(leadingSpan2):
close.append(None)
if len(high) < len(leadingSpan2):
high.append(None)
if len(low) < len(leadingSpan2):
low.append(None)
if len(volume) < len(leadingSpan2):
volume.append(None)
if len(baseLine) < len(leadingSpan2):
baseLine.append(None)
if len(changeLine) < len(leadingSpan2):
changeLine.append(None)
if len(laggingSpan) < len(leadingSpan2):
laggingSpan.append(None)
for i in range(26):
if len(leadingSpan1) < len(leadingSpan2):
leadingSpan1.append(leadingSpan1[-1])
# 9일 신고가
new_high_9 = [0 for c in range(8)] + [1 if (changeLine[c-1] is not None and changeLine[c] is not None and changeLine[c-1] < changeLine[c]) and None not in close[c-8:c+1] and max(close[c-8:c]) < close[c] else 0 for c in range(8, len(close))]
# 26일 신고가
new_high_26 = [0 for c in range(25)] + [1 if (baseLine[c-1] is not None and baseLine[c] is not None and baseLine[c-1] < baseLine[c]) and None not in close[c-8:c+1] and max(close[c-25:c]) < close[c] else 0 for c in range(25, len(close))]
# 9일 신저가
new_low_9 = [0 for c in range(8)] + [1 if (changeLine[c-1] is not None and changeLine[c] is not None and changeLine[c-1] < changeLine[c]) and None not in close[c-8:c+1] and close[c-9] < min(close[c-8:c+1]) else 0 for c in range(8, len(close))]
# 26일 신저가
new_low_26 = [0 for c in range(25)] + [1 if (baseLine[c-1] is not None and baseLine[c] is not None and baseLine[c-1] < baseLine[c]) and None not in close[c-8:c+1] and close[c-26] < min(close[c-25:c+1]) else 0 for c in range(25, len(close))]
# 이동 평균
close_df = pd.DataFrame(close)
avg5 = list(np.reshape(close_df.ewm(5).mean().values, -1))
avg10 = list(np.reshape(close_df.ewm(10).mean().values, -1))
avg20 = list(np.reshape(close_df.ewm(20).mean().values, -1))
avg60 = list(np.reshape(close_df.ewm(60).mean().values, -1))
avg90 = list(np.reshape(close_df.ewm(90).mean().values, -1))
avg120 = list(np.reshape(close_df.ewm(120).mean().values, -1))
avg240 = list(np.reshape(close_df.ewm(240).mean().values, -1))
avg360 = list(np.reshape(close_df.ewm(360).mean().values, -1))
avg480 = list(np.reshape(close_df.ewm(480).mean().values, -1))
avg720 = list(np.reshape(close_df.ewm(720).mean().values, -1))
avg1440 = list(np.reshape(close_df.ewm(1440).mean().values, -1))
avg2880 = list(np.reshape(close_df.ewm(2880).mean().values, -1))
np_high, np_low, np_close = np.array(high, dtype=np.float64), np.array(low, dtype=np.float64), np.array(close, dtype=np.float64)
slowk_12_df, slowd_12_df = talib.STOCH(np_high, np_low, np_close, fastk_period=12, slowk_period=5, slowk_matype=0, slowd_period=5, slowd_matype=0)
slowk_26_df, slowd_26_df = talib.STOCH(np_high, np_low, np_close, fastk_period=26, slowk_period=16, slowk_matype=0, slowd_period=16, slowd_matype=0)
slowk_52_df, slowd_52_df = talib.STOCH(np_high, np_low, np_close, fastk_period=52, slowk_period=32, slowk_matype=0, slowd_period=32, slowd_matype=0)
# 최고/최저 위치
loc_240 = [None for i in range(len(close))]
for i in range(240, len(close)):
min_v = np.min(result["close"][i-239:i+1])
max_v = np.max(result["close"][i-239:i+1])
if close[i] is not None:
loc_240[i] = ((close[i] - min_v) / (max_v - min_v))
else:
loc_240[i] = None
loc_240 = pd.DataFrame(loc_240)
loc_240_k = loc_240.to_numpy().reshape(-1)
loc_240_d = loc_240.rolling(20).mean()
loc_240_s = loc_240.rolling(60).mean()
loc_240_d = loc_240_d.to_numpy().reshape(-1)
loc_240_s = loc_240_s.to_numpy().reshape(-1)
# 볼린저 밴드
n, t = 10, 2
max_10 = close_df.rolling(window=n).mean()
stddev_10 = close_df.rolling(window=n).std()
upper_10 = max_10 + (stddev_10 * t) # 상단 볼리저 밴드
lower_10 = max_10 - (stddev_10 * t) # 하단 볼리저 밴드
middle_10 = (upper_10 + lower_10) / 2
upper_10 = list(np.reshape(upper_10.values, -1))
lower_10 = list(np.reshape(lower_10.values, -1))
middle_10 = list(np.reshape(middle_10.values, -1))
n, t = 20, 2
max_20 = close_df.rolling(window=n).mean()
stddev_20 = close_df.rolling(window=n).std()
upper_20 = max_20 + (stddev_20 * t) # 상단 볼리저 밴드
lower_20 = max_20 - (stddev_20 * t) # 하단 볼리저 밴드
middle_20 = (upper_20 + lower_20) / 2
upper_20 = list(np.reshape(upper_20.values, -1))
lower_20 = list(np.reshape(lower_20.values, -1))
middle_20 = list(np.reshape(middle_20.values, -1))
duration = 1440
if mins == 1440:
duration = 360
laggingSpan_close_diff, laggingSpan_close_diff_rate = self.getDiff_Rate(laggingSpan, close, duration=duration)
laggingSpan_avg60_diff, laggingSpan_avg60_diff_rate = self.getDiff_Rate(laggingSpan, avg60, duration=duration)
leadingSpan1_leadingSpan2_diff, leadingSpan1_leadingSpan2_diff_rate = self.getDiff_Rate(leadingSpan1, leadingSpan2, duration=duration)
df_list = [
pd.DataFrame(ymd),
pd.DataFrame(open), pd.DataFrame(close), pd.DataFrame(high), pd.DataFrame(low), pd.DataFrame(volume),
pd.DataFrame(changeLine), pd.DataFrame(baseLine), pd.DataFrame(laggingSpan), pd.DataFrame(leadingSpan1), pd.DataFrame(leadingSpan2),
pd.DataFrame(laggingSpan_close_diff),
pd.DataFrame(laggingSpan_avg60_diff),
pd.DataFrame(leadingSpan1_leadingSpan2_diff),
pd.DataFrame(laggingSpan_close_diff_rate),
pd.DataFrame(laggingSpan_avg60_diff_rate),
pd.DataFrame(leadingSpan1_leadingSpan2_diff_rate),
pd.DataFrame(loc_240_k), pd.DataFrame(loc_240_d), pd.DataFrame(loc_240_s),
pd.DataFrame(avg5), pd.DataFrame(avg10), pd.DataFrame(avg20), pd.DataFrame(avg60), pd.DataFrame(avg90), pd.DataFrame(avg120), pd.DataFrame(avg240), pd.DataFrame(avg360), pd.DataFrame(avg480), pd.DataFrame(avg720), pd.DataFrame(avg1440), pd.DataFrame(avg2880),
pd.DataFrame(upper_10), pd.DataFrame(lower_10), pd.DataFrame(middle_10),
pd.DataFrame(upper_20), pd.DataFrame(lower_20), pd.DataFrame(middle_20),
pd.DataFrame(new_high_9), pd.DataFrame(new_high_26),
pd.DataFrame(new_low_9), pd.DataFrame(new_low_26),
pd.DataFrame(slowk_12_df), pd.DataFrame(slowd_12_df),
pd.DataFrame(slowk_26_df), pd.DataFrame(slowd_26_df),
pd.DataFrame(slowk_52_df), pd.DataFrame(slowd_52_df),
]
data = pd.concat(df_list, axis=1)
column_names = [
'ymd',
'open', 'close', 'high', 'low', 'volume',
'changeLine', 'baseLine', 'laggingSpan', 'leadingSpan1', 'leadingSpan2',
'laggingSpan_close_diff',
'laggingSpan_avg60_diff',
'leadingSpan1_leadingSpan2_diff',
'laggingSpan_close_diff_rate',
'laggingSpan_avg60_diff_rate',
'leadingSpan1_leadingSpan2_diff_rate',
'loc_240_k', 'loc_240_d', 'loc_240_s',
'avg5', 'avg10', 'avg20', 'avg60', 'avg90', 'avg120', 'avg240', 'avg360', 'avg480', 'avg720', 'avg1440', 'avg2880',
'upper_10', 'lower_10', 'middle_10',
'upper_20', 'lower_20', 'middle_20',
'new_high_9', 'new_high_26',
'new_low_9', 'new_low_26',
'slowk_12', 'slowd_12',
'slowk_26', 'slowd_26',
'slowk_52', 'slowd_52',
]
data.columns = column_names
data.index = pd.DatetimeIndex(ymd)
return data, current_index
def getData(self, ticker, ymd=None, get_days=14):
if ymd is None:
result = self.getCoinData(ticker, get_days=get_days)
else:
result = self.getCoinData(ticker, ymd=ymd, get_days=get_days)
if len(result['ymd']) < 1:
return None, None
#result_tic = self.makeTickData(result_m1, mins=minute)
data, current_index = self.analyze(result)
return data, current_index
if __name__ == "__main__":
def min_max_normalize(data):
min_val = min(data)
max_val = max(data)
normalized_data = [(x - min_val) / (max_val - min_val) for x in data]
return normalized_data
# 예시 데이터
original_data = [-4, -3, -2, -1, 0]
normalized_data = min_max_normalize(original_data)
print(np.asarray(normalized_data)-1)
original_data = [0, 2,4,6,8,10]
normalized_data = min_max_normalize(original_data)
print(normalized_data)

View File

@@ -121,7 +121,7 @@ class FnGuideCrawler:
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()))
print("{}. {} ({}) {}".format(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)

View File

@@ -46,8 +46,8 @@ class MetaCrawler:
inputs.append({'NAME': 'RUB', 'CODE': 'FX_RUBKRW', 'URL': 'http://finance.naver.com/marketindex/exchangeDailyQuote.nhn?marketindexCd=FX_RUBKRW'}) # 러시아 RUB
inputs.append({'NAME': 'TWD', 'CODE': 'FX_TWDKRW', 'URL': 'http://finance.naver.com/marketindex/exchangeDailyQuote.nhn?marketindexCd=FX_TWDKRW'}) # 대만 TWD
for i in range(len(inputs)):
input = inputs[i]
for idx in range(len(inputs)):
input = inputs[idx]
NAME = input['NAME']
CODE = input['CODE']
@@ -100,7 +100,7 @@ class MetaCrawler:
finish = True
break
print(CODE, NAME, ymd)
print("{}. {} {} ({})".format(idx, ymd, CODE, NAME))
if finish:
break
@@ -191,7 +191,7 @@ class MetaCrawler:
finish = True
break
print ("20"+item[0])
print ("Trading_Trend 20{}".format(item[0]))
previousDay = html[0].values[2][0]
if finish:
break
@@ -271,7 +271,7 @@ class MetaCrawler:
finish = True
break
print("20"+item[0])
print("crawl_money_trend 20{}".format(item[0]))
if finish:
break
previousDay = html[0].values[2][0]
@@ -301,8 +301,8 @@ class MetaCrawler:
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]
for idx in range(len(inputs)):
input = inputs[idx]
NAME = input['NAME']
CODE = input['CODE']
@@ -357,7 +357,7 @@ class MetaCrawler:
if finish:
break
print(NAME + " / " + ymd)
print("{} {}".format(ymd, NAME))
conn.commit()
cursor.close()
@@ -393,8 +393,8 @@ class MetaCrawler:
inputs.append({'NAME': 'PLATINUM', 'CODE': 'CMDT_PL','URL': 'http://finance.naver.com/marketindex/worldDailyQuote.nhn?marketindexCd=CMDT_PL&fdtc=2'}) # 국제 백금
inputs.append({'NAME': 'PALADIUM', 'CODE': 'CMDT_PA','URL': 'http://finance.naver.com/marketindex/worldDailyQuote.nhn?marketindexCd=CMDT_PA&fdtc=2'}) # 국제 팔라듐
for i in range(len(inputs)):
input = inputs[i]
for idx in range(len(inputs)):
input = inputs[idx]
NAME = input['NAME']
CODE = input['CODE']
@@ -444,7 +444,7 @@ class MetaCrawler:
finish = True
break
print(CODE, NAME, ymd)
print("{}. {} {} ({})".format(idx, ymd, CODE, NAME))
if finish:
break

View File

@@ -132,10 +132,7 @@ class StockCrawler:
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 ymd FROM ' + tableName + ' WHERE CODE=? order by ymd desc', (stock["CODE"],))
result = cursor.fetchone()
ymd = self.START_DATE
@@ -153,6 +150,7 @@ class StockCrawler:
#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']))
print("{}. {} ({})".format(i, stock["CODE"], stock["NAME"]))
sleep(0.5)
conn.commit()
cursor.close()
@@ -178,7 +176,6 @@ class StockCrawler:
code_df = self.getStockInfo()
items = code_df.values
start_time = time.time()
idx = 0
for item in items:
idx += 1
@@ -211,9 +208,7 @@ class StockCrawler:
conn.commit()
cursor.close()
conn.close()
print(idx, item_name, item_code, (time.time() - start_time), "s")
start_time = time.time()
print("{}. {} ({})".format(idx, item_code, item_name))
sleep(0.3)
return
@@ -234,8 +229,6 @@ class StockCrawler:
cursor.close()
conn.close()
start_time = time.time()
pd.options.display.float_format = '{:.4f}'.format
pd.set_option('display.max_columns', None)
@@ -372,9 +365,8 @@ class StockCrawler:
conn.commit()
cursor.close()
conn.close()
print(idx, item_code, special_stocks[item_code], (time.time() - start_time), "s")
start_time = time.time()
print("{}. {} ({})".format(idx, item_code, special_stocks[item_code]))
sleep(0.05)
return