diff --git a/StockCrawler.py b/StockCrawler.py
index a97661d..c74e1cc 100644
--- a/StockCrawler.py
+++ b/StockCrawler.py
@@ -129,13 +129,6 @@ class StockCrawlerDaily:
analyzerSqlite = AnalyzerSqlite(stockFileName)
- print("\n[종목 분석]")
- # S: 분석까지 진행
- analyzerSqlite.analyzeDaily()
- analyzerSqlite.analyzeGrouping("weekly")
- analyzerSqlite.analyzeGrouping("monthly")
- self.bot.sendMsg("10. analyze...")
-
print("\n[종목 결정]")
# HTML 출력
outPath = os.path.join(self.PROJECT_HOME, "resources", "analysis")
@@ -154,7 +147,7 @@ class StockCrawlerDaily:
os.mkdir(outPath)
analyzerSqlite.findCandidates(outPath)
- self.bot.sendMsg("11. done decision...")
+ self.bot.sendMsg("10. done decision...")
return
diff --git a/hts/BuySell_Daily.py b/hts/BuySell_Daily.py
new file mode 100644
index 0000000..807de97
--- /dev/null
+++ b/hts/BuySell_Daily.py
@@ -0,0 +1,178 @@
+import numpy as np
+from datetime import datetime
+
+class BuySell_Daily:
+
+ def countYangBong(self, data, i):
+ count = 0
+ for c in range(5):
+ if data['open'][i-c] < data['close'][i-c]:
+ count += 1
+ return count
+
+ def getBuyPrice(self, data, i, BS=None):
+ buy_ymd, buy_price, buy_count, buy_weight, buy_type, buy_cut = None, 0, 0, 1, '', None
+
+ tmp_buy_ymd, tmp_buy_price, tmp_buy_count, tmp_buy_type, tmp_buy_cut = self.getBuyPrice_ichimok_changeLine(data, i, BS)
+ if 0 < tmp_buy_count:
+ buy_ymd = tmp_buy_ymd; buy_price = tmp_buy_price; buy_count = tmp_buy_count; buy_type = tmp_buy_type; buy_cut = tmp_buy_cut
+ tmp_buy_ymd, tmp_buy_price, tmp_buy_count, tmp_buy_type, tmp_buy_cut = self.getBuyPrice_ichimok_baseLine(data, i, BS)
+ if 0 < tmp_buy_count:
+ buy_ymd = tmp_buy_ymd; buy_price = tmp_buy_price; buy_count = tmp_buy_count; buy_type = tmp_buy_type; buy_cut = tmp_buy_cut
+ tmp_buy_ymd, tmp_buy_price, tmp_buy_count, tmp_buy_type, tmp_buy_cut = self.getBuyPrice_ichimok_laggingSpan(data, i, BS)
+ if 0 < tmp_buy_count:
+ buy_ymd = tmp_buy_ymd; buy_price = tmp_buy_price; buy_count = tmp_buy_count; buy_type = tmp_buy_type; buy_cut = tmp_buy_cut
+
+ return buy_ymd, buy_price, buy_count, buy_type, buy_cut
+
+ def getSellPrice(self, data, i, BS=None):
+ sell_price, sell_count, sell_type = 0, 1, ''
+ sell_type_list = []
+
+ tmp_sell_price, tmp_sell_type_list = self.getSellPrice_ichimok_baseLine(data, i, BS)
+ sell_type_list += tmp_sell_type_list
+
+ sell_price = tmp_sell_price
+
+ if 0 < len(sell_type_list) or 0 < sell_price:
+ sell_type = ','.join(list(set(sell_type_list)))
+
+ return sell_price, sell_count, sell_type
+
+ def getBuyPrice_ichimok_changeLine(self, data, i, BS=None):
+
+ buy_ymd, buy_price, buy_count, buy_weight, buy_type, buy_cut = None, 0, 0, 1, '', None
+
+ check = False
+
+ id9, id26, id33, id52 = 8, 25, 32, 51
+ if 5 < i:
+ # 신저가를 갱신하지 않으면서 전환선이 떨어질 때 주가는 올라감 (기준선은 횡보, 현재 봉이 신저가가 이닐 때)
+ # --> 기준선이 계속 횡보하거나 떨어지면 상승하지는 않는다.
+ # https://www.youtube.com/watch?v=KZMP0Ssv8WI&t=432s (8:45)
+ if data['new_low_9'][i] == 0:
+ if data['changeLine'][i] < data['baseLine'][i]:
+ if data['changeLine'][i] < data['changeLine'][i-1] and np.min(data['close'][i-8:i]) < data['close'][i]:
+ if data['baseLine'][i-1] == data['baseLine'][i] < data['baseLine'][i-2]:
+ if 3 < self.countYangBong(data, i):
+ check = True
+ buy_type = "ichimok_changeLine_1"
+ buy_weight = 5
+ buy_cut = min(np.min(data['open'][i - 60:i]), np.min(data['close'][i - 60:i]))
+
+ if data['new_high_9'][i] == 1:
+ if data['changeLine'][i-1] < data['changeLine'][i] and data['baseLine'][i-1] < data['baseLine'][i]:
+ if data['baseLine'][i - 1] != data['baseLine'][i]:
+ if 0.2 < data['leadingSpan1_leadingSpan2_diff_rate'][i+id52]:
+ check = True
+ buy_type = "ichimok_changeLine_2"
+ buy_weight = 10
+ buy_cut = min(np.min(data['open'][i - 60:i]), np.min(data['close'][i - 60:i]))
+
+ if data['new_high_26'][i] == 1:
+ for c in range(i-15, i):
+ if data['changeLine'][c-1] < data['baseLine'][c] and data['baseLine'][i-1] < data['changeLine'][i]:
+ if 0.2 < data['leadingSpan1_leadingSpan2_diff_rate'][i + id52]:
+ check = True
+ buy_type = "ichimok_changeLine_3"
+ buy_weight = 10
+ buy_cut = min(np.min(data['open'][i - 60:i]), np.min(data['close'][i - 60:i]))
+ break
+
+ if check:
+ buy_ymd = data['ymd'][i]
+ buy_price = data['close'][i]
+ buy_count = buy_weight
+
+ return buy_ymd, buy_price, buy_count, buy_type, buy_cut
+
+
+ """"""""""""""""""
+ """"""""""""""""""
+
+ def getBuyPrice_ichimok_baseLine(self, data, i, BS=None):
+
+ buy_ymd, buy_price, buy_count, buy_weight, buy_type, buy_cut = None, 0, 0, 1, '', None
+
+ check = False
+
+ id9, id26, id33, id52 = 9, 26, 33, 52
+ if 5 < i:
+ # 기준선이 하락할 때, 전환선이 상승하는 경우를 중기 추세의 변곡이라 한다
+ if data['changeLine'][i-1] < data['changeLine'][i] and data['baseLine'][i] < data['baseLine'][i-1]:
+ if data['changeLine'][i - 1] < data['baseLine'][i-1] and data['baseLine'][i] < data['changeLine'][i]:
+ if data['open'][i] < data['close'][i]:
+ if 3 < self.countYangBong(data, i):
+ check = True
+ buy_type = "ichimok_baseLine_1"
+ buy_weight = 5
+ buy_cut = min(np.min(data['open'][i - 60:i]), np.min(data['close'][i - 60:i]))
+
+ # 기준선이 평행 때, 전환선이 상승하는 경우를 중기 추세의 변곡이라 한다
+ if data['changeLine'][i-1] < data['changeLine'][i] and data['baseLine'][i-3] == data['baseLine'][i-2] == data['baseLine'][i-1] == data['baseLine'][i]:
+ if data['changeLine'][i - 1] < data['baseLine'][i-1] and data['baseLine'][i] < data['changeLine'][i]:
+ if data['open'][i] < data['close'][i]:
+ if 3 < self.countYangBong(data, i):
+ check = True
+ buy_type = "ichimok_baseLine_1"
+ buy_weight = 5
+ buy_cut = min(np.min(data['open'][i - 60:i]), np.min(data['close'][i - 60:i]))
+
+ if check:
+ buy_ymd = data['ymd'][i]
+ buy_price = data['close'][i]
+ buy_count = buy_weight
+
+ return buy_ymd, buy_price, buy_count, buy_type, buy_cut
+
+ """"""""""""""""""
+ """"""""""""""""""
+
+ def getBuyPrice_ichimok_laggingSpan(self, data, i, BS):
+
+ buy_ymd, buy_price, buy_count, buy_weight, buy_type, buy_cut = None, 0, 0, 1, '', None
+
+ check = False
+
+ if 5 < i:
+
+ if data['laggingSpan_close_diff_rate'][i-1] <= 0 and 0 < data['laggingSpan_close_diff_rate'][i]:
+ check = True
+ buy_price = data['close'][i]
+ buy_count = buy_weight
+ buy_weight = 2
+ buy_type = 'laggingSpan1'
+
+ if 0 <= data['laggingSpan_avg60_diff_rate'][i-1] and data['laggingSpan_avg60_diff_rate'][i] < 0:
+ check = True
+ buy_price = data['close'][i]
+ buy_count = buy_weight
+ buy_weight = 2
+ buy_type = 'laggingSpan2'
+
+ if check:
+ buy_price = data['close'][i]
+ buy_count = buy_weight
+
+ return buy_ymd, buy_price, buy_count, buy_type, buy_cut
+
+ """"""""""""""""""
+ """"""""""""""""""
+
+ def getSellPrice_ichimok_baseLine(self, data, i, BS=None):
+ sell_price = 0
+ sell_type_list = []
+
+ check = False
+
+ id26, id52 = 26, 52
+
+ if data['new_high_9'][i] == 0:
+ if data['baseLine'][i-1] < data['baseLine'][i] and data['changeLine'][i] < data['changeLine'][i-1]:
+ check = True
+ sell_type_list.append('ichimok_baseLine')
+
+ if check:
+ sell_price = data['close'][i]
+
+ return sell_price, sell_type_list
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index 88b9fe9..370f538 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,7 +4,7 @@ matplotlib
pandas_datareader
bs4
python-dateutil
-pywin32
+#pywin32
#datasets
#ipywidgets==7.0.0
@@ -17,7 +17,9 @@ pywin32
#transformers
yfinance
finterstellar
+pandas-datareader
pybithumb
ccxt
-slack_sdk
-scikit-learn
\ No newline at end of file
+slack-sdk
+scikit-learn
+ta-lib
diff --git a/stock/analysis/AnalyzerSqlite.py b/stock/analysis/AnalyzerSqlite.py
index 0532a90..2833490 100644
--- a/stock/analysis/AnalyzerSqlite.py
+++ b/stock/analysis/AnalyzerSqlite.py
@@ -4,11 +4,15 @@ import shutil
import matplotlib.pyplot as plt
import datetime
import sqlite3
-from datetime import datetime
+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
@@ -17,27 +21,11 @@ import plotly.graph_objs as go
from plotly import subplots
import plotly.io as po
-from statsmodels.tsa.seasonal import seasonal_decompose
-
from stock.analysis.Common import Common
-from stock.analysis.Stochastic import Stochastic
-from stock.analysis.BolingerBand import BolingerBand
-from stock.analysis.IchimokuCloud import IchimokuCloud
-from stock.analysis.RSI import RSI
-from stock.analysis.MACD import MACD
-from stock.analysis.Envelope import Envelope
-from stock.analysis.MFI import MFI
-from stock.analysis.MovingAverage import MovingAverage
class AnalyzerSqlite:
- stochastic = None
- bolingerBand = None
- ichimokuCloud = None
- rsi = None
- macd = None
- envelope = None
- mfi = None
-
+ jSDPattern = None
+ buySell_Daily = None
topCompany = None
fnguide = None
@@ -47,21 +35,15 @@ class AnalyzerSqlite:
moving_avg = None
- def __init__(self, stockFileName=None):
+ def __init__(self, RESOURCE_PATH):
self.common = Common()
- self.stochastic = Stochastic()
- self.bolingerBand = BolingerBand()
- self.ichimokuCloud = IchimokuCloud()
- self.rsi = RSI()
- self.macd = MACD()
- self.envelope = Envelope()
- self.mfi = MFI()
-
- if stockFileName is not None:
- self.stockFileName = stockFileName
- self.topCompany = self.getTopCompany(stockFileName, 2000)
- self.fnguide = self.readFnguide(stockFileName)
+ 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)
return
@@ -119,155 +101,378 @@ class AnalyzerSqlite:
conn.close()
return fnguide
- def draw(self, stock):
- # 참고) https://sjblog1.tistory.com/45
- ymd = list(stock['ymd'])
- open = list(stock['open'])
- close = list(stock['close'])
- high = list(stock['high'])
- low = list(stock['low'])
- volume = list(stock['volume'])
- avg3 = list(stock['avg3'])
- avg4 = list(stock['avg4'])
- avg5 = list(stock['avg5'])
- avg6 = list(stock['avg6'])
- avg10 = list(stock['avg10'])
- avg12 = list(stock['avg12'])
- avg20 = list(stock['avg20'])
- avg36 = list(stock['avg36'])
- avg40 = list(stock['avg40'])
- avg48 = list(stock['avg48'])
- avg60 = list(stock['avg60'])
- avg120 = list(stock['avg120'])
- avg240 = list(stock['avg240'])
- avg480 = list(stock['avg480'])
- disparity_avg5 = list(stock['disparity_avg5'])
- disparity_avg10 = list(stock['disparity_avg10'])
- disparity_avg20 = list(stock['disparity_avg20'])
- disparity_avg60 = list(stock['disparity_avg60'])
- disparity_avg120 = list(stock['disparity_avg120'])
- disparity_avg240 = list(stock['disparity_avg240'])
- disparity_avg480 = list(stock['disparity_avg480'])
- macd = list(stock['macd'])
- macdo = list(stock['macdo'])
- macds = list(stock['macds'])
- rsi = list(stock['rsi'])
- rsis = list(stock['rsis'])
- stochastic_slow_k = list(stock['slow_k'])
- stochastic_slow_d = list(stock['slow_d'])
- bolingerband_upper = list(stock['upper'])
- bolingerband_lower = list(stock['lower'])
- bolingerband_middle = list(stock['middle'])
- envelope_upper = list(stock['envelope_upper'])
- envelope_lower = list(stock['envelope_lower'])
- ichimokucloud_changeLine = list(stock['ichimokucloud_changeLine'])
- ichimokucloud_baseLine = list(stock['ichimokucloud_baseLine'])
- ichimokucloud_laggingSpan = [laggingSpan if -1 < laggingSpan else None for laggingSpan in stock['ichimokucloud_laggingSpan']]
- ichimokucloud_laggingSpan = list(ichimokucloud_laggingSpan)
- ichimokucloud_leadingSpan1 = list(stock['ichimokucloud_leadingSpan1'])
- ichimokucloud_leadingSpan2 = list(stock['ichimokucloud_leadingSpan2'])
- trend = list(stock['trend'])
- trend_s = list(stock['trend_s'])
- trend_k = list(stock['trend_k'])
- last_min = list(stock['last_min'])
- last_middle = list(stock['last_middle'])
- last_max = list(stock['last_max'])
+ def cz(self, value):
+ if value is None or math.isnan(value):
+ return 0
- # general
- candle_stick = go.Candlestick(x=ymd,
- open=open, high=high, low=low, close=close,
- increasing_line_color='red', decreasing_line_color='blue', name='candle')
- #avg3 = go.Scatter(x=ymd, y=avg3, name="avg3", line_color='#085F1B')
- #avg4 = go.Scatter(x=ymd, y=avg4, name="avg4", line_color='#085F1B')
- avg5 = go.Scatter(x=ymd, y=avg5, name="avg5", line_color='#ff0000')
- #avg6 = go.Scatter(x=ymd, y=avg6, name="avg6", line_color='#698D09')
- avg10 = go.Scatter(x=ymd, y=avg10, name="avg10", line_color='#8013ED')
- #avg12 = go.Scatter(x=ymd, y=avg12, name="avg12", line_color='#000000')
- avg20 = go.Scatter(x=ymd, y=avg20, name="avg20", line_color='#0000ff')
- #avg36 = go.Scatter(x=ymd, y=avg36, name="avg36", line_color='#370557')
- #avg40 = go.Scatter(x=ymd, y=avg40, name="avg40", line_color='#041366')
- #avg48 = go.Scatter(x=ymd, y=avg48, name="avg48", line_color='#7A1E66')
- avg60 = go.Scatter(x=ymd, y=avg60, name="avg60", line_color='#ff00ff')
- avg120 = go.Scatter(x=ymd, y=avg120, name="avg120", line_color='#cd4025')
- avg240 = go.Scatter(x=ymd, y=avg240, name="avg240", line_color='#38761d')
- avg480 = go.Scatter(x=ymd, y=avg480, name="avg480", line_color='#656565')
- bolinger_upper = go.Scatter(x=ymd, y=bolingerband_upper, name="bol_upper", line_color='#8B4513')
- bolinger_lower = go.Scatter(x=ymd, y=bolingerband_lower, name="bol_lower", line_color='#8B4513')
- env_upper = go.Scatter(x=ymd, y=envelope_upper, name="env_upper", line_color='#FF33A2')
- env_lower = go.Scatter(x=ymd, y=envelope_lower, name="env_lower", line_color='#FF33A2')
- changeLine = go.Scatter(x=ymd, y=ichimokucloud_changeLine, name="changeLine", line_color='#000000')
- baseLine = go.Scatter(x=ymd, y=ichimokucloud_baseLine, name="baseLine", line_color='#FF0000')
- laggingSpan = go.Scatter(x=ymd, y=ichimokucloud_laggingSpan, name='laggingSpan', line_color='#B50ABB')
- leadingSpan1 = go.Scatter(x=ymd, y=ichimokucloud_leadingSpan1, name='leadingSpan1', line_color='black')
- leadingSpan2 = go.Scatter(x=ymd, y=ichimokucloud_leadingSpan2, name='leadingSpan2', line_color='black')
- trend = go.Scatter(x=ymd, y=trend, name="trend", line_color='#574e4c')
- trend_k = go.Scatter(x=ymd, y=trend_k, name="trend_k", line_color='#ff0000')
- trend_s = go.Scatter(x=ymd, y=trend_s, name="trend_s", line_color='#0000ff')
- last_min = go.Scatter(x=ymd, y=last_min, name="last_min", line_color='#ff0000')
- last_middle = go.Scatter(x=ymd, y=last_middle, name="last_middle", line_color='#574e4c')
- last_max = go.Scatter(x=ymd, y=last_max, name="last_max", line_color='#0000ff')
+ return value
- candle_data = [trend, trend_k, trend_s, avg5, avg20, avg60, avg120, avg240, avg480, bolinger_upper, bolinger_lower, changeLine, baseLine, laggingSpan, last_min, last_max, last_middle, candle_stick]
- #candle_data = [candle_stick, trend, trend_k, trend_s, avg5, avg10, avg20, avg60, avg120, avg240, bolinger_upper, bolinger_lower, env_upper, env_lower, changeLine, baseLine]
- #candle_data = [avg5, avg20, trend, trend_k, trend_s, changeLine, baseLine, laggingSpan, candle_stick]
+ 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
- volume = go.Bar(x=ymd, y=volume, marker_color='red', name="volume")
- volume_data = [volume]
+ 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
- disparity_avg5 = go.Scatter(x=ymd, y=disparity_avg5, name="disparity_avg5", line_color='#ff0000')
- disparity_avg20 = go.Scatter(x=ymd, y=disparity_avg20, name="disparity_avg20", line_color='#0000ff')
- disparity_avg60 = go.Scatter(x=ymd, y=disparity_avg60, name="disparity_avg60", line_color='#ff00ff')
- disparity_avg120 = go.Scatter(x=ymd, y=disparity_avg120, name="disparity_avg120", line_color='#cd4025')
- disparity_avg240 = go.Scatter(x=ymd, y=disparity_avg240, name="disparity_avg240", line_color='#38761d')
- disparity_avg480 = go.Scatter(x=ymd, y=disparity_avg480, name="disparity_avg480", line_color='#656565')
- disparity_data = [disparity_avg5, disparity_avg20, disparity_avg60, disparity_avg120, disparity_avg240, disparity_avg480]
+ def draw(self, stock_code, data, bsLine=None):
- # macd
- macd_line = go.Scatter(x=ymd, y=macd, line=dict(color='red', width=2), name='macd')
- macd_s_line = go.Scatter(x=ymd, y=macds, line=dict(dash='dashdot', color='black', width=2), name='macds')
- macd_o_line = go.Bar(x=ymd, y=macdo, marker_color='purple', name='macdo')
- macd_data = [macd_line, macd_s_line, macd_o_line]
+ # 어제 데이터는 지운다.
+ #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 = [], [], [], []
- # stochastic
- rsi_line = go.Scatter(x=ymd, y=rsi, line=dict(color='red', width=2), name='rsi')
- rsis_line = go.Scatter(x=ymd, y=rsis, line=dict(dash='dashdot', color='black', width=2), name='rsis')
- rsi_data = [rsi_line, rsis_line]
+ 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']
- # stochastic
- stochastic_slow_k_line = go.Scatter(x=ymd, y=stochastic_slow_k, line=dict(color='red', width=2), name='slow_k')
- stochastic_slow_d_line = go.Scatter(x=ymd, y=stochastic_slow_d, line=dict(dash='dashdot', color='black', width=2), name='slow_d')
- stochastic_data = [stochastic_slow_k_line, stochastic_slow_d_line]
+ 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})
"
+ "avg5: {:.2f}, avg10: {:.2f}, avg20: {:.2f}, avg60: {:.2f}, avg90: {:.2f}, avg120: {:.2f}, avg240: {:.2f}
"
+ "avg360: {:.2f}, avg480: {:.2f}, avg720: {:.2f}, avg1440: {:.2f}, avg2880: {:.2f}
"
+ "loc_k: {:.2f}, loc_d: {:.2f}, loc_s: {:.2f}
"
+ "laggingSpan_close_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_changeLine_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_baseLine_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_leadingSpan1_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_leadingSpan2_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_avg60_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_lower10_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_middle10_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_upper10_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_lower20_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_middle20_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_upper20_diff: {:.4f} ({:.4f})
"
+ "baseLine_close_diff: {:.4f} ({:.4f})
"
+ "changeLine_close_diff: {:.4f} ({:.4f})
"
+ "changeLine_baseLine_diff: {:.4f} ({:.4f})
"
+ "leadingSpan1_leadingSpan2_diff: {:.4f} ({:.4f})
"
+ .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_changeLine_diff'][i]), self.cz(data['laggingSpan_changeLine_diff_rate'][i]),
+ self.cz(data['laggingSpan_baseLine_diff'][i]), self.cz(data['laggingSpan_baseLine_diff_rate'][i]),
+ self.cz(data['laggingSpan_leadingSpan1_diff'][i]), self.cz(data['laggingSpan_leadingSpan1_diff_rate'][i]),
+ self.cz(data['laggingSpan_leadingSpan2_diff'][i]), self.cz(data['laggingSpan_leadingSpan2_diff_rate'][i]),
+ self.cz(data['laggingSpan_avg60_diff'][i]), self.cz(data['laggingSpan_avg60_diff_rate'][i]),
+ self.cz(data['laggingSpan_lower10_diff'][i]), self.cz(data['laggingSpan_lower10_diff_rate'][i]),
+ self.cz(data['laggingSpan_middle10_diff'][i]), self.cz(data['laggingSpan_middle10_diff_rate'][i]),
+ self.cz(data['laggingSpan_upper10_diff'][i]), self.cz(data['laggingSpan_upper10_diff_rate'][i]),
+ self.cz(data['laggingSpan_lower20_diff'][i]), self.cz(data['laggingSpan_lower20_diff_rate'][i]),
+ self.cz(data['laggingSpan_middle20_diff'][i]), self.cz(data['laggingSpan_middle20_diff_rate'][i]),
+ self.cz(data['laggingSpan_upper20_diff'][i]), self.cz(data['laggingSpan_upper20_diff_rate'][i]),
+ self.cz(data['baseLine_close_diff'][i]), self.cz(data['baseLine_close_diff_rate'][i]),
+ self.cz(data['changeLine_close_diff'][i]), self.cz(data['changeLine_close_diff_rate'][i]),
+ self.cz(data['changeLine_baseLine_diff'][i]), self.cz(data['changeLine_baseLine_diff_rate'][i]),
+ self.cz(data['leadingSpan1_leadingSpan2_diff'][i]), self.cz(data['leadingSpan1_leadingSpan2_diff_rate'][i])
+ ))
+ sell_text_list.append(
+ "{}, {}, {} ({:,.2f})
"
+ "avg5: {:.2f}, avg10: {:.2f}, avg20: {:.2f}, avg60: {:.2f}, avg90: {:.2f}, avg120: {:.2f}, avg240: {:.2f}
"
+ "avg360: {:.2f}, avg480: {:.2f}, avg720: {:.2f}, avg1440: {:.2f}, avg2880: {:.2f}
"
+ "loc_k: {:.2f}, loc_d: {:.2f}, loc_s: {:.2f}
"
+ "laggingSpan_close_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_changeLine_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_baseLine_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_leadingSpan1_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_leadingSpan2_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_avg60_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_lower10_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_middle10_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_upper10_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_lower20_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_middle20_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_upper20_diff: {:.4f} ({:.4f})
"
+ "baseLine_close_diff: {:.4f} ({:.4f})
"
+ "changeLine_close_diff: {:.4f} ({:.4f})
"
+ "changeLine_baseLine_diff: {:.4f} ({:.4f})
"
+ "leadingSpan1_leadingSpan2_diff: {:.4f} ({:.4f})
"
+ .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_changeLine_diff'][i]), self.cz(data['laggingSpan_changeLine_diff_rate'][i]),
+ self.cz(data['laggingSpan_baseLine_diff'][i]), self.cz(data['laggingSpan_baseLine_diff_rate'][i]),
+ self.cz(data['laggingSpan_leadingSpan1_diff'][i]), self.cz(data['laggingSpan_leadingSpan1_diff_rate'][i]),
+ self.cz(data['laggingSpan_leadingSpan2_diff'][i]), self.cz(data['laggingSpan_leadingSpan2_diff_rate'][i]),
+ self.cz(data['laggingSpan_avg60_diff'][i]), self.cz(data['laggingSpan_avg60_diff_rate'][i]),
+ self.cz(data['laggingSpan_lower10_diff'][i]), self.cz(data['laggingSpan_lower10_diff_rate'][i]),
+ self.cz(data['laggingSpan_middle10_diff'][i]), self.cz(data['laggingSpan_middle10_diff_rate'][i]),
+ self.cz(data['laggingSpan_upper10_diff'][i]), self.cz(data['laggingSpan_upper10_diff_rate'][i]),
+ self.cz(data['laggingSpan_lower20_diff'][i]), self.cz(data['laggingSpan_lower20_diff_rate'][i]),
+ self.cz(data['laggingSpan_middle20_diff'][i]), self.cz(data['laggingSpan_middle20_diff_rate'][i]),
+ self.cz(data['laggingSpan_upper20_diff'][i]), self.cz(data['laggingSpan_upper20_diff_rate'][i]),
+ self.cz(data['baseLine_close_diff'][i]), self.cz(data['baseLine_close_diff_rate'][i]),
+ self.cz(data['changeLine_close_diff'][i]), self.cz(data['changeLine_close_diff_rate'][i]),
+ self.cz(data['changeLine_baseLine_diff'][i]), self.cz(data['changeLine_baseLine_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_changeLine_diff = go.Scatter(x=data['ymd'], y=data["laggingSpan_changeLine_diff"], name="laggingSpan_changeLine_diff", line_color='grey')
+ laggingSpan_baseLine_diff = go.Scatter(x=data['ymd'], y=data["laggingSpan_baseLine_diff"], name="laggingSpan_baseLine_diff", line_color='#d755e8')
+ laggingSpan_leadingSpan1_diff = go.Scatter(x=data['ymd'], y=data["laggingSpan_leadingSpan1_diff"], name="laggingSpan_leadingSpan1_diff", line_color='#d755e8')
+ laggingSpan_leadingSpan2_diff = go.Scatter(x=data['ymd'], y=data["laggingSpan_leadingSpan2_diff"], name="laggingSpan_leadingSpan2_diff", line_color='#d755e8')
+ laggingSpan_avg60_diff = go.Scatter(x=data['ymd'], y=data["laggingSpan_avg60_diff"], name="laggingSpan_avg60_diff", line_color='#d755e8')
+ laggingSpan_lower10_diff = go.Scatter(x=data['ymd'], y=data["laggingSpan_lower10_diff"], name="laggingSpan_lower10_diff", line_color='#d755e8')
+ laggingSpan_middle10_diff = go.Scatter(x=data['ymd'], y=data["laggingSpan_middle10_diff"], name="laggingSpan_middle10_diff", line_color='#d755e8')
+ laggingSpan_upper10_diff = go.Scatter(x=data['ymd'], y=data["laggingSpan_upper10_diff"], name="laggingSpan_upper10_diff", line_color='#d755e8')
+ laggingSpan_lower20_diff = go.Scatter(x=data['ymd'], y=data["laggingSpan_lower20_diff"], name="laggingSpan_lower20_diff", line_color='#d755e8')
+ laggingSpan_middle20_diff = go.Scatter(x=data['ymd'], y=data["laggingSpan_middle20_diff"], name="laggingSpan_middle20_diff", line_color='#d755e8')
+ laggingSpan_upper20_diff = go.Scatter(x=data['ymd'], y=data["laggingSpan_upper20_diff"], name="laggingSpan_upper20_diff", line_color='#d755e8')
+ baseLine_close_diff = go.Scatter(x=data['ymd'], y=data["baseLine_close_diff"], name="baseLine_close_diff", line_color='#d755e8')
+ changeLine_close_diff = go.Scatter(x=data['ymd'], y=data["changeLine_close_diff"], name="changeLine_close_diff", line_color='#d755e8')
+ changeLine_baseLine_diff = go.Scatter(x=data['ymd'], y=data["changeLine_baseLine_diff"], name="changeLine_baseLine_diff", line_color='#d755e8')
+ changeLine_leadingSpan1_diff = go.Scatter(x=data['ymd'], y=data["changeLine_leadingSpan1_diff"], name="changeLine_leadingSpan1_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_changeLine_diff_rate = go.Scatter(x=data['ymd'], y=data["laggingSpan_changeLine_diff_rate"], name="laggingSpan_changeLine_diff_rate", line_color='#d755e8')
+ laggingSpan_baseLine_diff_rate = go.Scatter(x=data['ymd'], y=data["laggingSpan_baseLine_diff_rate"], name="laggingSpan_baseLine_diff_rate", line_color='#d755e8')
+ laggingSpan_leadingSpan1_diff_rate = go.Scatter(x=data['ymd'], y=data["laggingSpan_leadingSpan1_diff_rate"], name="laggingSpan_leadingSpan1_diff_rate", line_color='#d755e8')
+ laggingSpan_leadingSpan2_diff_rate = go.Scatter(x=data['ymd'], y=data["laggingSpan_leadingSpan2_diff_rate"], name="laggingSpan_leadingSpan2_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')
+ laggingSpan_lower10_diff_rate = go.Scatter(x=data['ymd'], y=data["laggingSpan_lower10_diff_rate"], name="laggingSpan_lower10_diff_rate", line_color='#d755e8')
+ laggingSpan_middle10_diff_rate = go.Scatter(x=data['ymd'], y=data["laggingSpan_middle10_diff_rate"], name="laggingSpan_middle10_diff_rate", line_color='#d755e8')
+ laggingSpan_upper10_diff_rate = go.Scatter(x=data['ymd'], y=data["laggingSpan_upper10_diff_rate"], name="laggingSpan_upper10_diff_rate", line_color='#d755e8')
+ laggingSpan_lower20_diff_rate = go.Scatter(x=data['ymd'], y=data["laggingSpan_lower20_diff_rate"], name="laggingSpan_lower20_diff_rate", line_color='#d755e8')
+ laggingSpan_middle20_diff_rate = go.Scatter(x=data['ymd'], y=data["laggingSpan_middle20_diff_rate"], name="laggingSpan_middle20_diff_rate", line_color='#d755e8')
+ laggingSpan_upper20_diff_rate = go.Scatter(x=data['ymd'], y=data["laggingSpan_upper20_diff_rate"], name="laggingSpan_upper20_diff_rate", line_color='#d755e8')
+ baseLine_close_diff_rate = go.Scatter(x=data['ymd'], y=data["baseLine_close_diff_rate"], name="baseLine_close_diff_rate", line_color='#d755e8')
+ changeLine_close_diff_rate = go.Scatter(x=data['ymd'], y=data["changeLine_close_diff_rate"], name="changeLine_close_diff_rate", line_color='#d755e8')
+ changeLine_baseLine_diff_rate = go.Scatter(x=data['ymd'], y=data["changeLine_baseLine_diff_rate"], name="changeLine_baseLine_diff_rate", line_color='#d755e8')
+ changeLine_leadingSpan1_diff_rate = go.Scatter(x=data['ymd'], y=data["changeLine_leadingSpan1_diff_rate"], name="changeLine_leadingSpan1_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_high_33 = go.Scatter(x=data['ymd'], y=data["new_high_33"], name="new_high_33", line_color='#12A524')
+ new_high_52 = go.Scatter(x=data['ymd'], y=data["new_high_52"], name="new_high_52", line_color='#099B92')
+ 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')
+ new_low_33 = go.Scatter(x=data['ymd'], y=data["new_low_33"], name="new_low_33", line_color='#12A524')
+ new_low_52 = go.Scatter(x=data['ymd'], y=data["new_low_52"], name="new_low_52", line_color='#099B92')
+
+
+ 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(
+ "{}
"
+ "avg5: {:.2f}, avg10: {:.2f}, avg20: {:.2f}, avg60: {:.2f}, avg90: {:.2f}, avg120: {:.2f}, avg240: {:.2f}
"
+ "avg360: {:.2f}, avg480: {:.2f}, avg720: {:.2f}, avg1440: {:.2f}, avg2880: {:.2f}
"
+ "loc_k: {:.2f}, loc_d: {:.2f}, loc_s: {:.2f}
"
+ "laggingSpan_close_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_changeLine_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_baseLine_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_leadingSpan1_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_leadingSpan2_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_avg60_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_lower10_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_middle10_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_upper10_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_lower20_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_middle20_diff: {:.4f} ({:.4f})
"
+ "laggingSpan_upper20_diff: {:.4f} ({:.4f})
"
+ "baseLine_close_diff: {:.4f} ({:.4f})
"
+ "changeLine_close_diff: {:.4f} ({:.4f})
"
+ "changeLine_baseLine_diff: {:.4f} ({:.4f})
"
+ "leadingSpan1_leadingSpan2_diff: {:.4f} ({:.4f})
"
+ .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_changeLine_diff'][i]), self.cz(data['laggingSpan_changeLine_diff_rate'][i]),
+ self.cz(data['laggingSpan_baseLine_diff'][i]), self.cz(data['laggingSpan_baseLine_diff_rate'][i]),
+ self.cz(data['laggingSpan_leadingSpan1_diff'][i]), self.cz(data['laggingSpan_leadingSpan1_diff_rate'][i]),
+ self.cz(data['laggingSpan_leadingSpan2_diff'][i]), self.cz(data['laggingSpan_leadingSpan2_diff_rate'][i]),
+ self.cz(data['laggingSpan_avg60_diff'][i]), self.cz(data['laggingSpan_avg60_diff_rate'][i]),
+ self.cz(data['laggingSpan_lower10_diff'][i]), self.cz(data['laggingSpan_lower10_diff_rate'][i]),
+ self.cz(data['laggingSpan_middle10_diff'][i]), self.cz(data['laggingSpan_middle10_diff_rate'][i]),
+ self.cz(data['laggingSpan_upper10_diff'][i]), self.cz(data['laggingSpan_upper10_diff_rate'][i]),
+ self.cz(data['laggingSpan_lower20_diff'][i]), self.cz(data['laggingSpan_lower20_diff_rate'][i]),
+ self.cz(data['laggingSpan_middle20_diff'][i]), self.cz(data['laggingSpan_middle20_diff_rate'][i]),
+ self.cz(data['laggingSpan_upper20_diff'][i]), self.cz(data['laggingSpan_upper20_diff_rate'][i]),
+ self.cz(data['baseLine_close_diff'][i]), self.cz(data['baseLine_close_diff_rate'][i]),
+ self.cz(data['changeLine_close_diff'][i]), self.cz(data['changeLine_close_diff_rate'][i]),
+ self.cz(data['changeLine_baseLine_diff'][i]), self.cz(data['changeLine_baseLine_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_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]
+ 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_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,
+ new_high_9 ,new_high_26, new_high_33, new_high_52,new_low_9 ,new_low_26, new_low_33, new_low_52
+ ]
+ 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=6, cols=1,
- subplot_titles=("MACD", "스토캐스틱", "RSI", "이격도", "거래량", '캔들', ),
- # specs=[[{}], [{}], [{}], [{}], [{}], [{}]],
+ rows=5, cols=1,
+ subplot_titles=("이격도", "이격도 위치", "캔들", "slowkd", "거래량"),
shared_xaxes=True, horizontal_spacing=0.03, vertical_spacing=0.01,
- row_heights=[200, 200, 200, 200, 200, 800]
+ row_heights=[200, 200, 700, 200, 200]
)
- for trace in macd_data:
- fig.append_trace(trace, 1, 1)
- for trace in stochastic_data:
- fig.append_trace(trace, 2, 1)
- for trace in rsi_data:
- fig.append_trace(trace, 3, 1)
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)
- for trace in candle_data:
- fig.append_trace(trace, 6, 1)
- fig.update_layout(height=1900,
+ #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,
- xaxis4_rangeslider_visible=False,
- xaxis5_rangeslider_visible=False
+ xaxis2_rangeslider_visible=False,
+ xaxis3_rangeslider_visible=False,
+ xaxis4_rangeslider_visible=False
)
+ # 화면으로 출력함
return fig
+
def getPositionalEnergy(self, close):
# 260 (= 52 * 5)일 중 가장 찾은 금액과 가장 높았던 금액 중 현재가의 위치 계산
@@ -322,7 +527,7 @@ class AnalyzerSqlite:
return
- def writeFile(self, dir_name, CODE, NAME, top, stock, state):
+ def writeFile(self, outPath, CODE, NAME, top, stock, bsLine):
# 3년 이내 한번이라도 영업이익이 났는지 체크를 함
fnguide = None
if CODE in self.fnguide:
@@ -335,12 +540,11 @@ class AnalyzerSqlite:
check = True
if check:
- fig = self.draw(stock)
- title = "%s (%s), %d, %s 차트 (URL1, URL2, URL3)" % (NAME, CODE, stock['close'][0], dir_name, CODE, CODE, CODE)
+ fig = self.draw(CODE, stock, bsLine)
+ title = "%s (%s), 차트 (URL1, URL2, URL3)" % (NAME, CODE, CODE, CODE, CODE)
fig['layout'].update(title=title)
- fileName = self.outPath + "/" + dir_name
- fileName = "%s/%s_%s_%s_%s_%s.html" % (fileName, datetime.today().strftime("%Y%m%d"), state, top, NAME.replace(" ", ""), CODE)
+ 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
@@ -363,122 +567,10 @@ class AnalyzerSqlite:
return True
return False
- def getStockData(self, TableName, CODE):
- conn = sqlite3.connect(self.stockFileName)
- cursor = conn.cursor()
+ 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)
- sql = 'SELECT ymd, close, open, high, low, volume, '
- sql += ' avg3, avg4, avg5, avg6, avg10, avg12, avg20, avg36, avg40, avg48, avg60, avg120, avg200, avg240, avg300, avg360, avg480, avg720, avg1440, '
- sql += ' disparity_avg5, disparity_avg10, disparity_avg20, disparity_avg60, disparity_avg120, disparity_avg240, disparity_avg480, '
- sql += ' bolingerband_upper, bolingerband_lower, bolingerband_middle, bolingerband_width, bolingerband_pb, '
- sql += ' envelope_upper, envelope_lower, envelope_middle, '
- sql += ' ichimokucloud_changeLine, ichimokucloud_baseLine, ichimokucloud_laggingSpan, ichimokucloud_leadingSpan1, ichimokucloud_leadingSpan2, '
- sql += ' stochastic_fast_k, stochastic_slow_k, stochastic_slow_d, '
- sql += ' rsi, rsis, '
- sql += ' macd, macds, macdo, '
- sql += ' mfi, '
- sql += ' last_min, last_max, last_middle, '
- sql += ' trend, trend_k, trend_s '
- sql += ' FROM ' + TableName + ' where CODE=? order by ymd limit 1024 '
- cursor.execute(sql, (CODE,))
- prices = cursor.fetchall()
-
- cursor.close()
- conn.close()
-
- ymd = []
- close, open, high, low, volume = [], [], [], [], []
- avg3, avg4, avg5, avg6, avg10, avg12, avg20, avg36, avg40, avg48, avg60, avg120, avg200, avg240, avg300, avg360, avg480, avg720, avg1440 = [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []
- disparity_avg5, disparity_avg10, disparity_avg20, disparity_avg60, disparity_avg120, disparity_avg240, disparity_avg480 = [], [], [], [], [], [], []
- bolingerband_upper, bolingerband_lower, bolingerband_middle, bolingerband_width, bolingerband_pb = [], [], [], [], []
- envelope_upper, envelope_lower, envelope_middle = [], [], []
- ichimokucloud_changeLine, ichimokucloud_baseLine, ichimokucloud_laggingSpan, ichimokucloud_leadingSpan1, ichimokucloud_leadingSpan2 = [], [], [], [], []
- stochastic_fast_k, stochastic_slow_k, stochastic_slow_d = [], [], []
- rsi, rsis = [], []
- macd, macds, macdo = [], [], []
- mfi = []
- last_min, last_max, last_middle = [], [], []
- trend, trend_k, trend_s = [], [], []
-
- for price in prices:
- ymd.append(price[0])
- close.append(price[1])
- open.append(price[2])
- high.append(price[3])
- low.append(price[4])
- volume.append(price[5])
- avg3.append(price[6])
- avg4.append(price[7])
- avg5.append(price[8])
- avg6.append(price[9])
- avg10.append(price[10])
- avg12.append(price[11])
- avg20.append(price[12])
- avg36.append(price[13])
- avg40.append(price[14])
- avg48.append(price[15])
- avg60.append(price[16])
- avg120.append(price[17])
- avg200.append(price[18])
- avg240.append(price[19])
- avg300.append(price[20])
- avg360.append(price[21])
- avg480.append(price[22])
- avg720.append(price[23])
- avg1440.append(price[24])
- disparity_avg5.append(price[25])
- disparity_avg10.append(price[26])
- disparity_avg20.append(price[27])
- disparity_avg60.append(price[28])
- disparity_avg120.append(price[29])
- disparity_avg240.append(price[30])
- disparity_avg480.append(price[31])
- bolingerband_upper.append(price[32])
- bolingerband_lower.append(price[33])
- bolingerband_middle.append(price[34])
- bolingerband_width.append(price[35])
- bolingerband_pb.append(price[36])
- envelope_upper.append(price[37])
- envelope_lower.append(price[38])
- envelope_middle.append(price[39])
- ichimokucloud_changeLine.append(price[40])
- ichimokucloud_baseLine.append(price[41])
- ichimokucloud_laggingSpan.append(price[42])
- ichimokucloud_leadingSpan1.append(price[43])
- ichimokucloud_leadingSpan2.append(price[44])
- stochastic_fast_k.append(price[45])
- stochastic_slow_k.append(price[46])
- stochastic_slow_d.append(price[47])
- rsi.append(price[48])
- rsis.append(price[49])
- macd.append(price[50])
- macds.append(price[51])
- macdo.append(price[52])
- mfi.append(price[53])
- last_min.append(price[54])
- last_max.append(price[55])
- last_middle.append(price[56])
- trend.append(price[57])
- trend_k.append(price[58])
- trend_s.append(price[59])
-
- stock = {
- "ymd": ymd,
- "close": close, "open": open, "high": high, "low": low, "volume": volume,
- "avg3": avg3, "avg4": avg4, "avg5": avg5, "avg6": avg6, "avg10": avg10, "avg12": avg12, "avg20": avg20, "avg36": avg36, "avg40": avg40, "avg48": avg48, "avg60": avg60, "avg120": avg120, "avg200": avg200, "avg240": avg240, "avg300": avg300, "avg360": avg360, "avg480": avg480, "avg720": avg720, "avg1440": avg1440,
- "disparity_avg5": disparity_avg5, "disparity_avg10": disparity_avg10, "disparity_avg20": disparity_avg20, "disparity_avg60": disparity_avg60, "disparity_avg120": disparity_avg120, "disparity_avg240": disparity_avg240, "disparity_avg480": disparity_avg480,
- "upper": bolingerband_upper, "lower": bolingerband_lower, "middle": bolingerband_middle, "width": bolingerband_width, "pb": bolingerband_pb,
- "envelope_upper": envelope_upper, "envelope_lower": envelope_lower, "envelope_middle": envelope_middle,
- "ichimokucloud_changeLine": ichimokucloud_changeLine, "ichimokucloud_baseLine": ichimokucloud_baseLine, "ichimokucloud_laggingSpan": ichimokucloud_laggingSpan, "ichimokucloud_leadingSpan1": ichimokucloud_leadingSpan1, "ichimokucloud_leadingSpan2": ichimokucloud_leadingSpan2,
- "fast_k": stochastic_fast_k, "slow_k": stochastic_slow_k, "slow_d": stochastic_slow_d,
- "rsi": rsi, "rsis": rsis,
- "macd": macd, "macds": macds, "macdo": macdo,
- "mfi": mfi,
- "last_min": last_min, "last_max": last_max, "last_middle": last_middle,
- "trend": trend, "trend_k": trend_k, "trend_s": trend_s
- }
-
- return stock
+ return data_daily, ci_daily
def makeDir(self, dir_name):
@@ -487,30 +579,50 @@ class AnalyzerSqlite:
os.mkdir(self.outPath + "/" + dir_name)
return
- def makeDirectory(self, outPath):
- self.outPath = outPath
- if os.path.isdir(outPath):
- shutil.rmtree(outPath)
- os.mkdir(outPath)
+ def checkTransaction(self, ticker, data, ci):
- self.makeDir("monthly_env_하단_rsi_50")
+ # 어제 오늘 데이터로 분석
+ bsLine = {}
- self.makeDir("weekly_BB하단_내려옴")
+ 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)]
- self.makeDir("daily_이전에_없던_거래량")
- self.makeDir("daily_final_candidate")
+ size = ci
+ start = 0
+ for i in range(start, size):
+
+ # 매도 확인
+ sell_price, sell_count, sell_type = self.buySell_Daily.getSellPrice(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(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
- return
# 후보 찾기
def findCandidates(self, outPath):
- self.makeDirectory(outPath)
-
stockTableName = 'stock'
fnguideTableName = 'fnguide'
- stockAnalysisTableName = 'stock_analysis'
- stockAnalysisWeeklyTableName = 'stock_analysis_weekly'
- stockAnalysisMonthlyTableName = 'stock_analysis_monthly'
conn = sqlite3.connect(self.stockFileName)
cursor = conn.cursor()
@@ -522,522 +634,26 @@ class AnalyzerSqlite:
cursor.close()
conn.close()
- # 상승 종목 개수
- param = {'bull': [], 'bear': [], 'even': []}
- for i in range(60):
- param['bull'].append(0)
- param['bear'].append(0)
- param['even'].append(0)
- for idx, item in enumerate(items):
- CODE = item[0]
- stock_daily = self.getStockData(stockAnalysisTableName, CODE)
- for c in range(len(stock_daily['open'])):
- if c >= 60:
- break
- if stock_daily['open'][c] < stock_daily['close'][c]:
- param['bull'][c] += 1
- elif stock_daily['close'][c] < stock_daily['open'][c]:
- param['bear'][c] += 1
- else:
- param['even'][c] += 1
- self.writeSummary(param)
-
for idx, item in enumerate(items):
CODE = item[0]
NAME = item[1]
print("#", idx, ", CODE: ", CODE, ", NAME: ", NAME)
+ CODE = item[0]
+ stock_daily, ci = self.getStockData(CODE)
- top = "0"
- if CODE in self.topCompany:
- top = str(self.topCompany[CODE][0])
+ bsLine = self.checkTransaction(CODE, stock_daily, ci)
- stock_daily = self.getStockData(stockAnalysisTableName, CODE)
- stock_weekly = self.getStockData(stockAnalysisWeeklyTableName, CODE)
- stock_monthly = self.getStockData(stockAnalysisMonthlyTableName, CODE)
+ if bsLine['buy_ymd'][ci-1] is not None:
+ top = "0"
+ if CODE in self.topCompany:
+ top = str(self.topCompany[CODE][0])
- count = 0
- # 거래량이 10만 이상이고, 종가가 1천원 이상인지 체크 (https://happpy-rich.tistory.com/94)
- if stock_daily['volume'][-1] > 100000 and stock_daily['close'][-1] > 1000:
- # 종목 상태 체크 분석
-
- # Monthly 체크
- if len(stock_monthly['volume']) > 40:
-
- # ENV 하단 상향 돌파
- check = self.common.check_env_lower_rsi(stock_monthly)
- if check:
- count += 1
- dir_name = "monthly_env_하단_rsi_50"
- log = "RSI_" + "{:.2f}".format(stock_monthly['rsi'][-1])
- self.writeFile(dir_name, CODE, NAME, top, stock_monthly, log)
-
-
- # Weekly 체크
- if len(stock_weekly['volume']) > 40:
-
- # 볼린저 밴드 하단 아래
- check = self.common.check_under_BB_Low(stock_weekly)
- if check:
- count += 1
- dir_name = "weekly_BB하단_내려옴"
- log = "BB_" + str(top)
- self.writeFile(dir_name, CODE, NAME, top, stock_weekly, log)
-
- # 2) daily
- if len(stock_daily['volume']) > 100:
-
- # 52주 200일 기준 평균 + 50% 보다 높은 거래량의 경우
- check, log = self.common.check_volume(stock_daily)
- if check:
- count += 1
- dir_name = "daily_이전에_없던_거래량"
- log = "이전없던거래량_" + log
- self.writeFile(dir_name, CODE, NAME, top, stock_daily, log)
-
- check = self.common.check_optimal_buy_timeing(param, stock_daily)
- if check:
- count += 1
- dir_name = "daily_final_candidate"
- log = str(count) + "_" + dir_name + "_"
- self.writeFile(dir_name, CODE, NAME, top, stock_daily, log)
- return
-
- def get_moving_average(self, stock):
- q_3 = MovingAverage(3)
- q_4 = MovingAverage(4)
- q_5 = MovingAverage(5)
- q_6 = MovingAverage(6)
- q_10 = MovingAverage(10)
- q_12 = MovingAverage(12)
- q_20 = MovingAverage(20)
- q_30 = MovingAverage(30)
- q_36 = MovingAverage(36)
- q_40 = MovingAverage(40)
- q_48 = MovingAverage(48)
- q_60 = MovingAverage(60)
- q_120 = MovingAverage(120)
- q_200 = MovingAverage(200)
- q_240 = MovingAverage(240)
- q_300 = MovingAverage(300)
- q_360 = MovingAverage(360)
- q_480 = MovingAverage(480)
- q_720 = MovingAverage(720)
- q_1440 = MovingAverage(1440)
-
- for i in range(len(stock)):
- q_3.enqueue(stock[i]['close'])
- q_4.enqueue(stock[i]['close'])
- q_5.enqueue(stock[i]['close'])
- q_6.enqueue(stock[i]['close'])
- q_10.enqueue(stock[i]['close'])
- q_12.enqueue(stock[i]['close'])
- q_20.enqueue(stock[i]['close'])
- q_30.enqueue(stock[i]['close'])
- q_36.enqueue(stock[i]['close'])
- q_40.enqueue(stock[i]['close'])
- q_48.enqueue(stock[i]['close'])
- q_60.enqueue(stock[i]['close'])
- q_120.enqueue(stock[i]['close'])
- q_200.enqueue(stock[i]['close'])
- q_240.enqueue(stock[i]['close'])
- q_300.enqueue(stock[i]['close'])
- q_360.enqueue(stock[i]['close'])
- q_480.enqueue(stock[i]['close'])
- q_720.enqueue(stock[i]['close'])
- q_1440.enqueue(stock[i]['close'])
-
- stock[i]['avg3'] = q_3.avg()
- stock[i]['avg4'] = q_4.avg()
- stock[i]['avg5'] = q_5.avg()
- stock[i]['avg6'] = q_6.avg()
- stock[i]['avg10'] = q_10.avg()
- stock[i]['avg12'] = q_12.avg()
- stock[i]['avg20'] = q_20.avg()
- stock[i]['avg30'] = q_30.avg()
- stock[i]['avg36'] = q_36.avg()
- stock[i]['avg40'] = q_40.avg()
- stock[i]['avg48'] = q_48.avg()
- stock[i]['avg60'] = q_60.avg()
- stock[i]['avg120'] = q_120.avg()
- stock[i]['avg200'] = q_200.avg()
- stock[i]['avg240'] = q_240.avg()
- stock[i]['avg300'] = q_300.avg()
- stock[i]['avg360'] = q_360.avg()
- stock[i]['avg480'] = q_480.avg()
- stock[i]['avg720'] = q_720.avg()
- stock[i]['avg1440'] = q_1440.avg()
-
- return
-
- def get_disparity(self, stock):
- for i in range(len(stock)):
- stock[i]['disparity_avg5'] = 100 * (stock[i]["open"] / stock[i]["avg5"])
- stock[i]['disparity_avg10'] = 100 * (stock[i]["open"] / stock[i]["avg10"])
- stock[i]['disparity_avg20'] = 100 * (stock[i]["open"] / stock[i]["avg20"])
- stock[i]['disparity_avg60'] = 100 * (stock[i]["open"] / stock[i]["avg60"])
- stock[i]['disparity_avg120'] = 100 * (stock[i]["open"] / stock[i]["avg120"])
- stock[i]['disparity_avg240'] = 100 * (stock[i]["open"] / stock[i]["avg240"])
- stock[i]['disparity_avg480'] = 100 * (stock[i]["open"] / stock[i]["avg480"])
-
- return
-
- def convertFormat(self, weekDict):
- previous_close = 0
- stock_price = []
- for ts in weekDict['open']:
- stock_price.append(
- {
- "ymd": ts.strftime("%Y.%m.%d"),
- "close": weekDict['close'][ts],
- "diff": weekDict['close'][ts] - previous_close,
- "open": weekDict['open'][ts],
- "high": weekDict['high'][ts],
- "low": weekDict['low'][ts],
- "volume": weekDict['volume'][ts],
- "avg3": -1,
- "avg4": -1,
- "avg5": -1,
- "avg6": -1,
- "avg10": -1,
- "avg12": -1,
- "avg20": -1,
- "avg30": -1,
- "avg36": -1,
- "avg40": -1,
- "avg48": -1,
- "avg60": -1,
- "avg120": -1,
- "avg200": -1,
- "avg240": -1,
- "avg300": -1,
- "avg360": -1,
- "avg480": -1,
- "avg720": -1,
- "avg1440": -1,
- "disparity_avg5": -1,
- "disparity_avg10": -1,
- "disparity_avg20": -1,
- "disparity_avg60": -1,
- "disparity_avg120": -1,
- "disparity_avg240": -1,
- "disparity_avg480": -1,
- "bolingerband_upper": -1,
- "bolingerband_lower": -1,
- "bolingerband_middle": -1,
- "bolingerband_width": -1,
- "bolingerband_pb": -1,
- "ichimokucloud_changeLine": -1,
- "ichimokucloud_baseLine": -1,
- "ichimokucloud_leadingSpan1": -1,
- "ichimokucloud_leadingSpan2": -1,
- "stochastic_fast_k": -1,
- "stochastic_slow_k": -1,
- "stochastic_slow_d": -1,
- "rsi": -1,
- "rsis": -1,
- "macd": -1,
- "macds": -1,
- "macdo": -1,
- "mfi": -1,
- "last_min": -1,
- "last_max": -1,
- "last_middle": -1,
- "trend": -1,
- "trend_k": -1,
- "trend_s": -1
- }
- )
- previous_close = weekDict['close'][ts]
-
- return stock_price
-
- def analyzeAdditionalInfo(self, stock, cursor, type=None):
- if type==None:
- stockAnalysisTableName = 'stock_analysis'
- else:
- stockAnalysisTableName = 'stock_analysis_' + type
-
- # 테이블 생성
- cursor.execute("CREATE TABLE IF NOT EXISTS " + stockAnalysisTableName + " (CODE text, NAME text, ymd text, close REAL, diff REAL, open REAL, high REAL, low REAL, volume REAL, avg3 REAL, avg4 REAL, avg5 REAL, avg6 REAL, avg10 REAL, avg12 REAL, avg20 REAL, avg36 REAL, avg40 REAL, avg48 REAL, avg60 REAL, avg120 REAL, avg200 REAL, avg240 REAL, avg300 REAL, avg360 REAL, avg480 REAL, avg720 REAL, avg1440 REAL, disparity_avg5 REAL, disparity_avg10 REAL, disparity_avg20 REAL, disparity_avg60 REAL, disparity_avg120 REAL, disparity_avg240 REAL, disparity_avg480, bolingerband_upper REAL, bolingerband_lower REAL, bolingerband_middle REAL, bolingerband_width REAL, bolingerband_pb REAL, envelope_upper REAL, envelope_lower REAL, envelope_middle REAL, ichimokucloud_changeLine REAL, ichimokucloud_baseLine REAL, ichimokucloud_laggingSpan REAL, ichimokucloud_leadingSpan1 REAL, ichimokucloud_leadingSpan2 REAL, stochastic_fast_k REAL, stochastic_slow_k REAL, stochastic_slow_d REAL, rsi REAL, rsis REAL, macd REAL, macds REAL, macdo REAL, mfi REAL, last_min REAL, last_max REAL, last_middle REAL, trend REAL, trend_k REAL, trend_s REAL)")
-
- # 키 생성
- create_key = "CREATE INDEX IF NOT EXISTS " + stockAnalysisTableName + "_idx on " + stockAnalysisTableName + " (CODE, ymd) "
- cursor.execute(create_key)
-
- # 이동 평균 계산
- stock["PRICE"] = sorted(stock["PRICE"], key=lambda x: x['ymd'])
- self.get_moving_average(stock["PRICE"])
-
- # 이동 평균을 이용한 이격도 계산
- self.get_disparity(stock["PRICE"])
-
- self.ichimokuCloud.analyze(stock)
- self.stochastic.analyze(stock)
- self.bolingerBand.analyze(stock)
- self.envelope.analyze(stock)
- self.rsi.analyze(stock)
- self.macd.analyze(stock)
- self.mfi.analyze(stock)
-
- close_list = [price['close'] for price in stock['PRICE']]
- if 200 < len(close_list):
- # 트렌드: 실시간 정상 작동 안됨
- size = int(len(close_list) / 100)
- pos = round(size / 2)
- close_temp = close_list + [close_list[-1]] * pos
- decomposition_results = seasonal_decompose(close_temp, model='multiplicative', period=size)
- trend = decomposition_results.trend[:-pos]
- trend_df = pd.DataFrame(trend).fillna(close_list[0])
- trend_list = trend_df.values.tolist()
- for i, price in enumerate(stock['PRICE']):
- price['trend'] = trend_list[i][0]
-
- trend_s_df = trend_df.rolling(120).mean()
- trend_s_list = trend_s_df.values.tolist()
- for i, price in enumerate(stock['PRICE']):
- price['trend_s'] = trend_s_list[i][0]
-
- trend_k_df = trend_df.rolling(5).mean()
- trend_k_list = trend_k_df.values.tolist()
- for i, price in enumerate(stock['PRICE']):
- price['trend_k'] = trend_k_list[i][0]
-
-
- size = int(len(close_list) / 25)
- pos = round(size / 2)
- close_temp = close_list + [close_list[-1]] * pos
- decomposition_results = seasonal_decompose(close_temp, model='multiplicative', period=size)
- trend = decomposition_results.trend[:-pos]
- trend_df = pd.DataFrame(trend).fillna(close_list[0])
- trend_list = trend_df.values.tolist()
- for i, price in enumerate(stock['PRICE']):
- price['trend'] = trend_list[i][0]
- else:
- for i, price in enumerate(stock['PRICE']):
- price['trend'] = stock['PRICE'][i]['avg120']
- price['trend_s'] = stock['PRICE'][i]['avg120']
- price['trend_k'] = stock['PRICE'][i]['avg120']
-
-
- last_min = np.array([np.min(close_list[i - 60:i]) if 19 < i else np.min(close_list[:i+1]) for i in range(len(close_list))])
- last_max = np.array([np.max(close_list[i - 60:i]) if 19 < i else np.max(close_list[:i+1]) for i in range(len(close_list))])
- last_middle = (last_max + last_min) / 2
- for i, price in enumerate(stock['PRICE']):
- price['last_min'] = last_min[i]
- price['last_max'] = last_max[i]
- price['last_middle'] = last_middle[i]
-
- sorted_stock = sorted(stock["PRICE"], key=lambda x: x['ymd'], reverse=True)
- for price in sorted_stock:
- cursor.execute('SELECT * FROM ' + stockAnalysisTableName + ' WHERE CODE=? and ymd=?', (stock['CODE'], price['ymd'],))
- result = cursor.fetchone()
- if result == None:
- sql = "INSERT INTO " + stockAnalysisTableName + "(CODE, NAME, ymd, close, diff, open, high, low, volume, "
- sql += " avg3, avg4, avg5, avg6, avg10, avg12, avg20, avg36, avg40, avg48, avg60, avg120, avg200, avg240, avg300, avg360, avg480, avg720, avg1440, "
- sql += " disparity_avg5, disparity_avg10, disparity_avg20, disparity_avg60, disparity_avg120, disparity_avg240, disparity_avg480, "
- sql += " bolingerband_upper, bolingerband_lower, bolingerband_middle, bolingerband_width, bolingerband_pb, "
- sql += " envelope_upper, envelope_lower, envelope_middle, "
- sql += " ichimokucloud_changeLine, ichimokucloud_baseLine, ichimokucloud_laggingSpan, ichimokucloud_leadingSpan1, ichimokucloud_leadingSpan2, "
- sql += " stochastic_fast_k, stochastic_slow_k, stochastic_slow_d, "
- sql += " rsi, rsis, macd, macds, macdo, "
- sql += " mfi, "
- sql += " last_min, last_max, last_middle, "
- sql += " trend, trend_k, trend_s) "
- sql += " VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
-
- cursor.execute(sql, (
- stock["CODE"], stock["NAME"], price['ymd'], price['close'], price['diff'], price['open'], price['high'], price['low'], price['volume'],
- price['avg3'], price['avg4'], price['avg5'], price['avg6'], price['avg10'], price['avg12'], price['avg20'], price['avg36'], price['avg40'], price['avg48'], price['avg60'], price['avg120'], price['avg200'], price['avg240'], price['avg300'], price['avg360'], price['avg480'], price['avg720'], price['avg1440'],
- price['disparity_avg5'], price['disparity_avg10'], price['disparity_avg20'], price['disparity_avg60'], price['disparity_avg120'], price['disparity_avg240'], price['disparity_avg480'],
- price['bolingerband_upper'], price['bolingerband_lower'], price['bolingerband_middle'], price['bolingerband_width'], price['bolingerband_pb'],
- price['envelope_upper'], price['envelope_lower'], price['envelope_middle'],
- price['ichimokucloud_changeLine'], price['ichimokucloud_baseLine'], price['ichimokucloud_laggingSpan'], price['ichimokucloud_leadingSpan1'], price['ichimokucloud_leadingSpan2'],
- price['stochastic_fast_k'], price['stochastic_slow_k'], price['stochastic_slow_d'],
- price['rsi'], price['rsis'], price['macd'], price['macds'], price['macdo'],
- price['mfi'],
- price['last_min'], price['last_max'], price['last_middle'],
- price['trend'],price['trend_k'],price['trend_s'],
- ))
-
- else:
- sql = "UPDATE " + stockAnalysisTableName + " SET close=?, diff=?, open=?, high=?, low=?, volume=?, "
- sql += " avg3=?, avg4=?, avg5=?, avg6=?, avg10=?, avg12=?, avg20=?, avg36=?, avg40=?, avg48=?, avg60=?, avg120=?, avg200=?, avg240=?, avg300=?, avg360=?, avg480=?, avg720=?, avg1440=?, "
- sql += " disparity_avg5=?, disparity_avg10=?, disparity_avg20=?, disparity_avg60=?, disparity_avg120=?, disparity_avg240=?, disparity_avg480=?, "
- sql += " bolingerband_upper=?, bolingerband_lower=?, bolingerband_middle=?, bolingerband_width=?, bolingerband_pb=?,"
- sql += " envelope_upper=?, envelope_lower=?, envelope_middle=?, "
- sql += " ichimokucloud_changeLine=?, ichimokucloud_baseLine=?, ichimokucloud_laggingSpan=?, ichimokucloud_leadingSpan1=?, ichimokucloud_leadingSpan2=?, "
- sql += " stochastic_fast_k=?, stochastic_slow_k=?, stochastic_slow_d=?, "
- sql += " rsi=?, rsis=?, "
- sql += " macd=?, macds=?, macdo=?, "
- sql += " mfi=?, "
- sql += " last_min=?, last_max=?, last_middle=?, "
- sql += " trend=?, trend_k=?, trend_s=? "
- sql += " WHERE CODE=? and ymd=?"
-
- cursor.execute(sql,
- (price['close'], price['diff'], price['open'], price['high'], price['low'], price['volume'],
- price['avg3'], price['avg4'], price['avg5'], price['avg6'], price['avg10'], price['avg12'], price['avg20'], price['avg36'], price['avg40'], price['avg48'], price['avg60'], price['avg120'], price['avg200'], price['avg240'], price['avg300'], price['avg360'], price['avg480'], price['avg720'], price['avg1440'],
- price['disparity_avg5'], price['disparity_avg10'], price['disparity_avg20'], price['disparity_avg60'], price['disparity_avg120'], price['disparity_avg240'], price['disparity_avg480'],
- price['bolingerband_upper'], price['bolingerband_lower'], price['bolingerband_middle'], price['bolingerband_width'], price['bolingerband_pb'],
- price['envelope_upper'], price['envelope_lower'], price['envelope_middle'],
- price['ichimokucloud_changeLine'], price['ichimokucloud_baseLine'], price['ichimokucloud_laggingSpan'], price['ichimokucloud_leadingSpan1'], price['ichimokucloud_leadingSpan2'],
- price['stochastic_fast_k'], price['stochastic_slow_k'], price['stochastic_slow_d'],
- price['rsi'], price['rsis'],
- price['macd'], price['macds'], price['macdo'],
- price['mfi'],
- price['last_min'], price['last_max'], price['last_middle'],
- price['trend'], price['trend_k'], price['trend_s'],
- stock["CODE"], price['ymd'],))
- break
-
- cursor.execute("commit",)
- return
-
- def setItem(self, item):
- return {
- "ymd": item[0],
- "close": item[1],
- "diff": item[2],
- "open": item[3],
- "high": item[4],
- "low": item[5],
- "volume": item[6],
- "avg3": -1,
- "avg4": -1,
- "avg5": -1,
- "avg6": -1,
- "avg10": -1,
- "avg12": -1,
- "avg20": -1,
- "avg36": -1,
- "avg40": -1,
- "avg48": -1,
- "avg60": -1,
- "avg120": -1,
- "avg200": -1,
- "avg240": -1,
- "avg300": -1,
- "avg360": -1,
- "avg480": -1,
- "avg720": -1,
- "avg1440": -1,
- "disparity_avg5": -1,
- "disparity_avg10": -1,
- "disparity_avg20": -1,
- "disparity_avg60": -1,
- "disparity_avg120": -1,
- "disparity_avg240": -1,
- "disparity_avg480": -1,
- "bolingerband_upper": -1,
- "bolingerband_lower": -1,
- "bolingerband_middle": -1,
- "bolingerband_width": -1,
- "bolingerband_pb": -1,
- "envelope_upper": -1,
- "envelope_lower": -1,
- "envelope_middle": -1,
- "ichimokucloud_changeLine": -1,
- "ichimokucloud_baseLine": -1,
- "ichimokucloud_laggingSpan": -1,
- "ichimokucloud_leadingSpan1": -1,
- "ichimokucloud_leadingSpan2": -1,
- "stochastic_fast_k": -1,
- "stochastic_slow_k": -1,
- "stochastic_slow_d": -1,
- "rsi": -1,
- "rsis": -1,
- "macd": -1,
- "macds": -1,
- "macdo": -1,
- "mfi": -1,
- "last_min": -1,
- "last_max": -1,
- "last_middle": -1,
- "trend": -1,
- "trend_k": -1,
- "trend_s": -1
- }
-
- def analyzeDaily(self):
- stockTableName = 'stock'
-
- conn = sqlite3.connect(self.stockFileName)
- cursor = conn.cursor()
-
- cursor.execute('SELECT distinct code, name FROM ' + stockTableName + ' order by code')
- items = cursor.fetchall()
-
- for rowid, item in enumerate(items):
-
- stock = {"CODE": item[0], "NAME": item[1], "PRICE":[]}
- print("Daily # :", rowid, ", CODE: ", stock['CODE'], ", NAME: ", stock['NAME'])
-
- sql = 'SELECT ymd, close, diff, open, high, low, volume FROM ' + stockTableName + ' where CODE=? order by ymd '
- sql += ' limit 500'
- cursor.execute(sql, (stock['CODE'],))
- items = cursor.fetchall()
-
- for item in items:
- stock['PRICE'].append( self.setItem(item) )
-
- self.analyzeAdditionalInfo(stock, cursor)
-
- conn.commit()
- cursor.close()
- conn.close()
-
- return
-
-
- def analyzeGrouping(self, type):
- stockTableName = 'stock'
-
- conn = sqlite3.connect(self.stockFileName)
- cursor = conn.cursor()
-
- cursor.execute('SELECT distinct code, name FROM ' + stockTableName + ' order by code')
- items = cursor.fetchall()
-
- for rowid, item in enumerate(items):
- stock = {"CODE": item[0], "NAME": item[1], "PRICE": []}
- print(type, "# :", rowid, ", CODE: ", stock['CODE'], ", NAME: ", stock['NAME'])
-
- sql = 'SELECT ymd, close, diff, open, high, low, volume FROM ' + stockTableName + ' where CODE=? order by ymd '
- #sql += ' limit 350'
- cursor.execute(sql, (stock['CODE'],))
- items = cursor.fetchall()
-
- for item in items:
- stock['PRICE'].append(
- self.setItem(item)
- )
-
- agg_dict = {'open': 'first',
- 'high': 'max',
- 'low': 'min',
- 'close': 'last',
- 'volume': 'sum'}
-
- df = pd.DataFrame(stock['PRICE'])
- df['ymd'] = pd.to_datetime(df['ymd'])
- df.set_index('ymd', inplace=True)
-
- if type == "weekly":
- condition="W"
- else:
- condition='M'
- df_group = df.resample(condition).agg(agg_dict)
- df_group = df_group.dropna()
- df_group.merge(df, )
- stock['PRICE'] = self.convertFormat(df_group.to_dict())
-
- self.analyzeAdditionalInfo(stock, cursor, type)
-
- conn.commit()
- cursor.close()
- conn.close()
+ # 거래량이 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)
return
@@ -1047,12 +663,8 @@ if __name__ == "__main__":
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')
- stockFileName = os.path.join(RESOURCE_PATH, 'stock.db')
- analyzer = AnalyzerSqlite(stockFileName)
+ analyzer = AnalyzerSqlite(RESOURCE_PATH)
- analyzer.analyzeDaily()
- analyzer.analyzeGrouping("weekly")
- analyzer.analyzeGrouping("monthly")
# HTML 출력
outPath = os.path.join(PROJECT_HOME, "resources", "analysis")
diff --git a/stock/analysis/JSDPattern.py b/stock/analysis/JSDPattern.py
new file mode 100644
index 0000000..d2951da
--- /dev/null
+++ b/stock/analysis/JSDPattern.py
@@ -0,0 +1,571 @@
+# 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)
\ No newline at end of file
diff --git a/stock/analysis/JSDPattern_realtime.py b/stock/analysis/JSDPattern_realtime.py
new file mode 100644
index 0000000..39b5973
--- /dev/null
+++ b/stock/analysis/JSDPattern_realtime.py
@@ -0,0 +1,255 @@
+# 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 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)
\ No newline at end of file
diff --git a/stock/analysis/JSDPattern_simulation.py b/stock/analysis/JSDPattern_simulation.py
new file mode 100644
index 0000000..e57b5d9
--- /dev/null
+++ b/stock/analysis/JSDPattern_simulation.py
@@ -0,0 +1,366 @@
+# 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 JSDPattern import JSDPattern
+
+class JSDPattern_simulation (JSDPattern):
+
+ def __init__(self, RESOURCE_PATH=None):
+ super().__init__(RESOURCE_PATH)
+ return
+
+ 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, 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)
\ No newline at end of file