init
This commit is contained in:
@@ -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...")
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user