From d5e5316fce92b5c9f331cd4c87af146bc357a9e2 Mon Sep 17 00:00:00 2001 From: dsyoon Date: Fri, 26 Apr 2024 07:47:48 +0900 Subject: [PATCH] init --- HTS_Alert.py | 50 -- HTS_etf_122630.py | 31 - HTS_etf_233740.py | 31 - HTS_etf_251340.py | 31 - HTS_etf_252670.py | 31 - HTS_etf_all.py | 80 --- HTS_etf_long.py | 400 ------------ HTS_etf_short.py | 358 ----------- HTS_stocks.py | 181 ------ JSDPattern.py | 274 +++++++++ JSDPattern_daily.py | 769 ++++++++++++++++++++++++ JSDPattern_minutely.py | 641 ++++++++++++++++++++ LabelMaker.py | 130 ---- Simulation.py | 273 --------- StockCrawler.py | 26 - StockPredictorAPI.py | 7 - StockTrainer.py | 65 -- VitTrainer.py | 240 -------- stock/analysis/AnalyzerSqlite.py | 594 ------------------ stock/analysis/JSDPattern.py | 571 ------------------ stock/analysis/JSDPattern_realtime.py | 255 -------- stock/analysis/JSDPattern_simulation.py | 288 --------- stock/crawler/FnGuideCrawler.py | 2 +- stock/crawler/MetaCrawler.py | 22 +- stock/crawler/StockCrawler.py | 14 +- 25 files changed, 1699 insertions(+), 3665 deletions(-) delete mode 100644 HTS_Alert.py delete mode 100644 HTS_etf_122630.py delete mode 100644 HTS_etf_233740.py delete mode 100644 HTS_etf_251340.py delete mode 100644 HTS_etf_252670.py delete mode 100644 HTS_etf_all.py delete mode 100644 HTS_etf_long.py delete mode 100644 HTS_etf_short.py delete mode 100644 HTS_stocks.py create mode 100644 JSDPattern.py create mode 100644 JSDPattern_daily.py create mode 100644 JSDPattern_minutely.py delete mode 100644 LabelMaker.py delete mode 100644 Simulation.py delete mode 100644 StockPredictorAPI.py delete mode 100644 StockTrainer.py delete mode 100755 VitTrainer.py delete mode 100644 stock/analysis/AnalyzerSqlite.py delete mode 100644 stock/analysis/JSDPattern.py delete mode 100644 stock/analysis/JSDPattern_realtime.py delete mode 100644 stock/analysis/JSDPattern_simulation.py diff --git a/HTS_Alert.py b/HTS_Alert.py deleted file mode 100644 index 6542b9a..0000000 --- a/HTS_Alert.py +++ /dev/null @@ -1,50 +0,0 @@ -import time -import requests -from bs4 import BeautifulSoup -from datetime import datetime -from stock.util.TelegramBot import TelegramBot - -class HTS_Alert : - bot = None - - def __init__(self): - self.bot = TelegramBot() - return - - def checkPrice(self, code): - code_index = 0 - PERCENT = ["50%", "50%"] - CHECK_PRICE = [2565, 2422] - - THIS_TIME = datetime.now() - today = datetime.today().strftime('%Y%m%d') - while datetime.strptime(today + " 080000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 151500", '%Y%m%d %H%M%S'): - url = 'https://finance.naver.com/item/main.naver?code={code}'.format(code=code.strip()) - res = requests.get(url) - - html = res.text - soup = BeautifulSoup(html, 'html.parser') - post = soup.select_one('#chart_area > .rate_info > .today > .no_today > em') - arr = post.text.split("\n") - c_price = int(arr[1].replace(',', '')) - - if c_price < CHECK_PRICE[code_index]: - self.bot.sendMsg(code + " " + str(CHECK_PRICE[code_index]) + " " + PERCENT[code_index] + "를 파세요...") - code_index += 1 - - if code_index > len(CHECK_PRICE): - break - - time.sleep(60) - THIS_TIME = datetime.now() - return - -if __name__ == "__main__": - hTS_Alert = HTS_Alert() - - week = datetime.today().weekday() - if week in (0, 1, 2, 3, 4): # 0:월, 1:화, 2:수, 3:목, 4:금, 5:토, 6:일 - - post = hTS_Alert.checkPrice('252670') - - print ("done...") \ No newline at end of file diff --git a/HTS_etf_122630.py b/HTS_etf_122630.py deleted file mode 100644 index 1f51a1b..0000000 --- a/HTS_etf_122630.py +++ /dev/null @@ -1,31 +0,0 @@ -import os -from datetime import datetime -from HTS_etf import HTS_etf - -if __name__ == "__main__": - today = datetime.today() - - PROJECT_HOME = os.getcwd() - RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources") - - # KODEX 인버스 * 2 - stock_code = "122630" - stock_name = "KODEX 레버리지" - - hts = HTS_etf(RESOURCE_PATH, stock_code, stock_name, SELL_GAP=80) - hts.connect2DB("hts.db") - - today_str = today.strftime('%Y%m%d') - - if not os.path.exists(os.path.join(RESOURCE_PATH, "log")): - os.mkdir(os.path.join(RESOURCE_PATH, "log")) - - MAX_PRICE = 500000 - hts.buyRealTime(today_str, MAX_PRICE=MAX_PRICE) - - db_filename = os.path.join(RESOURCE_PATH, "hts.db") - hts.insertStockData(today, stock_code, stock_name) - - hts.disconnect() - hts.bot.sendMsg("done... {} ({})".format(stock_code, stock_name)) - print("done...") \ No newline at end of file diff --git a/HTS_etf_233740.py b/HTS_etf_233740.py deleted file mode 100644 index 80049af..0000000 --- a/HTS_etf_233740.py +++ /dev/null @@ -1,31 +0,0 @@ -import os -from datetime import datetime -from HTS_etf import HTS_etf - -if __name__ == "__main__": - today = datetime.today() - - PROJECT_HOME = os.getcwd() - RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources") - - # KODEX 인버스 * 2 - stock_code = "233740" - stock_name = "KODEX 코스닥150레버리지" - - hts = HTS_etf(RESOURCE_PATH, stock_code, stock_name, SELL_GAP=70) - hts.connect2DB("hts.db") - - today_str = today.strftime('%Y%m%d') - - if not os.path.exists(os.path.join(RESOURCE_PATH, "log")): - os.mkdir(os.path.join(RESOURCE_PATH, "log")) - - MAX_PRICE = 500000 - hts.buyRealTime(today_str, MAX_PRICE=MAX_PRICE) - - db_filename = os.path.join(RESOURCE_PATH, "hts.db") - hts.insertStockData(today, stock_code, stock_name) - - hts.disconnect() - hts.bot.sendMsg("done... {} ({})".format(stock_code, stock_name)) - print("done...") \ No newline at end of file diff --git a/HTS_etf_251340.py b/HTS_etf_251340.py deleted file mode 100644 index 495c4fe..0000000 --- a/HTS_etf_251340.py +++ /dev/null @@ -1,31 +0,0 @@ -import os -from datetime import datetime -from HTS_etf import HTS_etf - -if __name__ == "__main__": - today = datetime.today() - - PROJECT_HOME = os.getcwd() - RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources") - - # KODEX 인버스 * 2 - stock_code = "251340" - stock_name = "KODEX 코스닥150선물인버스" - - hts = HTS_etf(RESOURCE_PATH, stock_code, stock_name, SELL_GAP=50) - hts.connect2DB("hts.db") - - today_str = today.strftime('%Y%m%d') - - if not os.path.exists(os.path.join(RESOURCE_PATH, "log")): - os.mkdir(os.path.join(RESOURCE_PATH, "log")) - - MAX_PRICE = 500000 - hts.buyRealTime(today_str, MAX_PRICE=MAX_PRICE) - - db_filename = os.path.join(RESOURCE_PATH, "hts.db") - hts.insertStockData(today, stock_code, stock_name) - - hts.disconnect() - hts.bot.sendMsg("done... {} ({})".format(stock_code, stock_name)) - print("done...") \ No newline at end of file diff --git a/HTS_etf_252670.py b/HTS_etf_252670.py deleted file mode 100644 index c7e701c..0000000 --- a/HTS_etf_252670.py +++ /dev/null @@ -1,31 +0,0 @@ -import os -from datetime import datetime -from HTS_etf import HTS_etf - -if __name__ == "__main__": - today = datetime.today() - - PROJECT_HOME = os.getcwd() - RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources") - - # KODEX 인버스 * 2 - stock_code = "252670" - stock_name = "KODEX 200선물인버스2X" - - hts = HTS_etf(RESOURCE_PATH, stock_code, stock_name, SELL_GAP=30) - hts.connect2DB("hts.db") - - today_str = today.strftime('%Y%m%d') - - if not os.path.exists(os.path.join(RESOURCE_PATH, "log")): - os.mkdir(os.path.join(RESOURCE_PATH, "log")) - - MAX_PRICE = 500000 - hts.buyRealTime(today_str, MAX_PRICE=MAX_PRICE) - - db_filename = os.path.join(RESOURCE_PATH, "hts.db") - hts.insertStockData(today, stock_code, stock_name) - - hts.disconnect() - hts.bot.sendMsg("done... {} ({})".format(stock_code, stock_name)) - print("done...") \ No newline at end of file diff --git a/HTS_etf_all.py b/HTS_etf_all.py deleted file mode 100644 index 02e3316..0000000 --- a/HTS_etf_all.py +++ /dev/null @@ -1,80 +0,0 @@ -import os -import json -import time -import psutil -from datetime import datetime -from HTS_etf import HTS_etf - -if __name__ == "__main__": - - PROJECT_HOME = os.getcwd() - RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources") - - stocks = [ - {'stock_code': '122630', 'stock_name': 'KODEX 레버리지'}, - {'stock_code': '233740', 'stock_name': 'KODEX 코스닥150레버리지'}, - {'stock_code': '251340', 'stock_name': 'KODEX 코스닥150선물인버스'}, - {'stock_code': '252670', 'stock_name': 'KODEX 200선물인버스2X'} - ] - - hts = HTS_etf(RESOURCE_PATH) - hts.connect2DB("hts.db") - - today = datetime.today().strftime('%Y%m%d') - - if not os.path.exists(os.path.join(RESOURCE_PATH, "log")): - os.mkdir(os.path.join(RESOURCE_PATH, "log")) - - BUY_LIST = {} - for stock in stocks: - with open("config.json", "r", encoding="utf-8") as f: - config = json.load(f) - - if stock['stock_code'] not in BUY_LIST: - BUY_LIST[stock['stock_code']] = {} - - BUY_LIST[stock['stock_code']]['MAX_BUY_PRICE'] = config['MAX_BUY_PRICE'] - BUY_LIST[stock['stock_code']]['BUY_LIST_1'] = config['BUY_LIST_1'] - BUY_LIST[stock['stock_code']]['BUY_LIST_1']["disparity"] = hts.getDisparityLimit(stock) - - print("START...") - close_data = {} - INIT = True - while datetime.strptime(today + " 060000", '%Y%m%d %H%M%S') < datetime.now() < datetime.strptime(today + " 153100", '%Y%m%d %H%M%S'): - if datetime.strptime(today + " 090000", '%Y%m%d %H%M%S') < datetime.now() < datetime.strptime(today + " 151500", '%Y%m%d %H%M%S'): - THIS_TIME = datetime.now() - for stock in stocks: - if datetime.strptime(today + " 090000", '%Y%m%d %H%M%S') < datetime.now() < datetime.strptime(today + " 090100", '%Y%m%d %H%M%S'): - hts.bot.sendMsg("START... {} ({}) SLOW_K: {}".format(stock['stock_code'], stock['stock_name'], BUY_LIST[stock['stock_code']]['MAX_BUY_PRICE'])) - - LAST_DATA = hts.getLastData(stock['stock_code'], today) - result_m1 = hts.getRealTime(stock['stock_code'], today, LAST_DATA) - result_tic_m1 = hts.makeTickData1(result_m1, mins=1) - data = hts.analyze(result_tic_m1) - result_tic_m30 = hts.makeTickData2(result_tic_m1, mins=30) - data_signal = hts.analyze(result_tic_m30) - # data.drop(data.index[:len(data) - analyzed_day], inplace=True) - - hts.buyRealTime(stock, data, data_signal, BUY_LIST[stock['stock_code']]['MAX_BUY_PRICE'], BUY_LIST[stock['stock_code']]['BUY_LIST_1']) - close_data[stock['stock_code']] = data['close'][-1] - - if INIT: - hts.bot.sendMsg("Alive... close: {}".format(str(close_data))) - INIT = False - - if int(THIS_TIME.strftime("%M")) % 50 == 0: - vm = psutil.virtual_memory() - vm_item = dict() - vm_item['free'] = vm.available // (1024 * 1024) - vm_item['idle'] = vm.available / vm.total * 100 - hts.bot.sendMsg("Alive... close: {}, mem: {:.1f}".format(str(close_data), vm_item['idle'])) - - time.sleep(60) - - db_filename = os.path.join(RESOURCE_PATH, "hts.db") - for stock in stocks: - hts.insertStockData(today, stock['stock_code'], stock['stock_name']) - hts.disconnect() - - hts.bot.sendMsg("done...") - print("done...") \ No newline at end of file diff --git a/HTS_etf_long.py b/HTS_etf_long.py deleted file mode 100644 index c6ecb51..0000000 --- a/HTS_etf_long.py +++ /dev/null @@ -1,400 +0,0 @@ -import time -import os -import math -import sqlite3 -from datetime import datetime, timedelta - -from hts.HTS import HTS -from hts.OrderType import OrderType - -from hts.BuySellChecker import BuySellChecker -from hts.OrderChecker import OrderChecker -from stock.util.LabelChecker import LabelChecker -from stock.util.TelegramBot import TelegramBot -from stock.analysis.StockStatus import StockStatus - -class HTS_etf (HTS): - - RESOURCE_PATH = None - stock_code = None - buy_count = None - orderChecker = None - buySellChecker = None - labelChecker = None - bot = None - stockStatus = None - - def __init__(self, RESOURCE_PATH): - super().__init__(RESOURCE_PATH) - - self.RESOURCE_PATH = RESOURCE_PATH - - self.orderChecker = OrderChecker(self.RESOURCE_PATH, "ETF") - self.buySellChecker = BuySellChecker() - self.labelChecker = LabelChecker(RESOURCE_PATH) - self.bot = TelegramBot() - self.stockStatus = StockStatus(RESOURCE_PATH) - - return - - def connect2StockDB(self): - - self.conn_stock = sqlite3.connect(os.path.join(self.RESOURCE_PATH, "resources/stock.db")) - self.cursor_stock = self.conn_stock.cursor() - - return - - def disconnectStockDB(self): - - self.cursor_stock.close() - self.conn_stock.close() - return - - def sellStocks(self, stock_code=None, bs_sell_price=None): - check = False - jangoDic = self.requstJango() - if jangoDic and len(jangoDic.keys()) > 0: - for code in jangoDic: - if stock_code is not None: - if code == "A"+stock_code and bs_sell_price is not None: - if jangoDic[code]['매도가능'] > 0: - if 2 < jangoDic[code]['평가손익']: - self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], bs_sell_price) - self.bot.post(code, jangoDic[code]['종목명'], "SELL", bs_sell_price, jangoDic[code]['매도가능']) - check = True - else: - continue - else: - if jangoDic[code]['매도가능'] > 0: - if 3 < jangoDic[code]['평가손익']: - # 3% 이상 시 수익 매도 - currentStock = self.currentStock(code[1:]) - self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], currentStock['close']) - self.bot.post(code, jangoDic[code]['종목명'], "SELL", currentStock['close'], jangoDic[code]['매도가능']) - check = True - return check - - - def getSellingPrice(self, log_time, stock_code, final_price, without_loss=False): - # final_price와 diff를 받으면, 해당 가격으로 그냥 매도한다는 의미 - # final_price와 diff가 None이면 장부가와 final 중 max로 팔겠다는 의미 - # final_price가 0이고 diff가 None이면 장부가로 팔겠다는 의미임 - orderNum = None - jangoDic = self.requstJango() - if jangoDic and len(jangoDic.keys()) > 0: - for code in jangoDic: - if jangoDic[code]['매도가능'] > 0: - if without_loss: - if jangoDic[code]['장부가']*0.07 < jangoDic[code]['장부가'] - final_price: - sell_price = jangoDic[code]['장부가'] - if code == "A" + stock_code: - orderNum = self.requestOrder(OrderType.sell, stock_code, jangoDic[code]['매도가능'], sell_price) - return orderNum, log_time.strftime('%Y%m%d %H%M%S'), jangoDic[code]['매도가능'], sell_price - else: - max_price = max(jangoDic[code]['장부가'], final_price) - sell_price = (int(max_price) - int(max_price) % 5) + 5 - if code == "A"+stock_code: - orderNum = self.requestOrder(OrderType.sell, stock_code, jangoDic[code]['매도가능'], sell_price) - return orderNum, log_time.strftime('%Y%m%d %H%M%S'), jangoDic[code]['매도가능'], sell_price - return orderNum, None, None, None - - - def makeTickData(self, data, mins=30): - result = {"check": set(), - "time": [], - "open": [], - "close": [], - "high": [], - "low": [], - "vol": [], - "label": []} - - for i in range(mins, len(data['time'])+1): - result["check"].add(data['time'][i-1]) - result["time"].append(data['time'][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["vol"].append(sum(data['vol'][i - mins: i])) - - return result - - def getStockType(self, stock_code, short=False): - slow_k, p_slow_k, slow_k_week, p_slow_k_week, slow_k_month, p_slow_k_month = -1, -1, -1, -1, -1, -1 - - self.cursor_stock.execute('select stochastic_slow_k, max(ymd) from stock_analysis where code=? group by 1 order by ymd desc',(stock_code,)) - items = self.cursor_stock.fetchall() - if items is not None and len(items) > 1: - for i, item in enumerate(items): - if i == 0: - slow_k = item[0] - elif i == 1: - p_slow_k = item[0] - else: - break - - self.cursor_stock.execute('select stochastic_slow_k, max(ymd) from stock_analysis_weekly where code=? group by 1 order by ymd desc', (stock_code, )) - items = self.cursor_stock.fetchall() - if items is not None and len(items) > 1: - for i, item in enumerate(items): - if i == 0: - slow_k_week = item[0] - elif i == 1: - p_slow_k_week = item[0] - else: - break - - self.cursor_stock.execute('select stochastic_slow_k, max(ymd) from stock_analysis_monthly where code=? group by 1 order by ymd desc',(stock_code,)) - items = self.cursor_stock.fetchall() - if items is not None and len(items) > 1: - for i, item in enumerate(items): - if i == 0: - slow_k_month = item[0] - elif i == 1: - p_slow_k_month = item[0] - else: - break - - if slow_k is None or p_slow_k is None: - slow_k , p_slow_k = -1, -1 - if slow_k_week is None or p_slow_k_week is None: - slow_k_week, p_slow_k_week = -1, -1 - if slow_k_month is None or p_slow_k_month is None: - slow_k_month, p_slow_k_month = -1, -1 - - - type_stock = {'day':1, 'week':10, 'month':100} - - if stock_code == "^KS11": - if slow_k < 20: type_stock['day'] = 10 - if 20 < slow_k < 25: type_stock['day'] = 7.5 - if 25 < slow_k < 30: type_stock['day'] = 5 - if 30 < slow_k < 35: type_stock['day'] = 2.5 - - if slow_k_week < 20: type_stock['week'] = 100 - if 20 < slow_k_week < 25: type_stock['week'] = 75 - if 25 < slow_k_week < 30: type_stock['week'] = 50 - if 30 < slow_k_week < 35: type_stock['week'] = 25 - - if slow_k_month < 20: type_stock['month'] = 1000 - if 20 < slow_k_month < 25: type_stock['month'] = 750 - if 25 < slow_k_month < 30: type_stock['month'] = 500 - if 30 < slow_k_month < 35: type_stock['month'] = 250 - else: - if slow_k < 10: type_stock['day'] = 10 - if 10 < slow_k < 15: type_stock['day'] = 7.5 - if 15 < slow_k < 20: type_stock['day'] = 5 - if 20 < slow_k < 25: type_stock['day'] = 2.5 - - if slow_k_week < 10: type_stock['week'] = 100 - if 10 < slow_k_week < 15: type_stock['week'] = 75 - if 15 < slow_k_week < 20: type_stock['week'] = 50 - if 20 < slow_k_week < 25: type_stock['week'] = 25 - - if slow_k_month < 10: type_stock['month'] = 1000 - if 10 < slow_k_month < 15: type_stock['month'] = 750 - if 15 < slow_k_month < 20: type_stock['month'] = 500 - if 20 < slow_k_month < 25: type_stock['month'] = 250 - - return type_stock - - def getBuyCount(self, bs_buy_price, kospi_type, stock_type): - - base_price = 10000 - log_base = 1.2 - p_k_m, p_k_w, p_k_d, p_s_m, p_s_w, p_s_d = 0.3, 0.2, 0.05, 0.25, 0.18, 0.02 - weight_1, weight_2, weight_3, weight_4, weight_5 = 0.5, 0.3, 0.14, 0.05, 0.01 - kospi_weight = weight_5 - if kospi_type['day'] == 10: kospi_weight = weight_1 - if kospi_type['day'] == 7.5: kospi_weight = weight_2 - if kospi_type['day'] == 5: kospi_weight = weight_3 - if kospi_type['day'] == 2.5: kospi_weight = weight_4 - stock_weight = weight_5 - if stock_type['day'] == 10: stock_weight = weight_1 - if stock_type['day'] == 7.5: stock_weight = weight_2 - if stock_type['day'] == 5: stock_weight = weight_3 - if stock_type['day'] == 2.5: stock_weight = weight_4 - - max_price = math.log( - kospi_weight * p_k_m * kospi_type['month'] + - kospi_weight * p_k_w * kospi_type['week'] + - kospi_weight * p_k_d * kospi_type['day'] + - stock_weight * p_s_m * stock_type['month'] + - stock_weight * p_s_w * stock_type['week'] + - stock_weight * p_s_d * stock_type['day'], log_base) * base_price - - buy_count = 0 - if max_price > 1: - buy_count = int(math.floor(max_price / bs_buy_price)) - - return buy_count - - def buyRealTime(self, today, stocks, analyzed_day=1000): - - print ("START...") - THIS_TIME = datetime.now() - kospi_type = self.getStockType("^KS11", short=False) - - LAST_DATA = {} - for stock in stocks: - LAST_DATA[stock['stock_code']] = self.getLastData(stock['stock_code'], today) - - while datetime.strptime(today + " 070000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 153100", '%Y%m%d %H%M%S'): - - if datetime.strptime(today + " 090000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 151500", '%Y%m%d %H%M%S'): - - # 매도를 체크한다. - # self.sellStocks() - - for idx, stock in enumerate(stocks): - - time.sleep(0.1) - - print("%5d: %8s, %-50s"%(idx, stock['stock_code'], stock['stock_name'])) - - try: - # 데이터를 가지고 온다. - data = self.getRealTime(stock['stock_code'], today, LAST_DATA[stock['stock_code']]) - except: - print("#ERROR:", stock['stock_code'], stock['stock_name']) - continue - - # 현재 매수가 - bs_buy_price = data["close"][len(data["close"]) - 1] - - # 미체결 기록을 가져와서 10분 이상 된 매수 주문을 취소 한다. - ORDER_LIST = self.requestOrderList() - orderListToCancel = self.orderChecker.cancel(today, "A" + stock['stock_code'], ORDER_LIST, mins=10) - if len(orderListToCancel) > 0: - self.cancelOrderList(orderListToCancel) - - if bs_buy_price > 1000: - - if not self.orderChecker.exist(today, "A" + stock['stock_code'], hours=5): - stock_type = self.getStockType(stock['stock_code'], short=False) - buy_count = self.getBuyCount(bs_buy_price, kospi_type, stock_type) - - if buy_count > 0: - # 매수를 주문한다. - orderNum = self.requestOrder(OrderType.buy, stock['stock_code'], buy_count , bs_buy_price) - self.orderChecker.buy(today, "A" + stock['stock_code'], buy_count, bs_buy_price, orderNum) - - # bot에 메시지를 보냄 - self.bot.post(stock['stock_code'], stock['stock_name'], "BUY", bs_buy_price, buy_count) - - # 로그 출력 - print("BUY", THIS_TIME.strftime('%Y%m%d %H%M%S'), orderNum, stock['stock_code'], stock['stock_name'], bs_buy_price, buy_count) - - # 로그 출력 - print("TIMECHECK: %s, code: %s, name: %s, buy: %d, avg5: %.2f, avg30: %.2f, open: %d, high: %d, low: %d, slow_k: %.2f" % - (str(THIS_TIME), stock['stock_code'], stock['stock_name'], bs_buy_price, data["avg5"][0], data["avg30"][0], - data["open"][0], data["high"][0], data["low"][0], data["slow_k"][0])) - - """ - elif datetime.strptime(today + " 151530", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 151600", '%Y%m%d %H%M%S'): - # 3시 15분 30초부터 3시 16분 사이는 잔량을 매도한다. - - if not final_sell_check: - #### - # 손해 보지 않는 가격에 매도한다. - #### - - for stock in stocks: - # 주문 리스트를 가져온다. - orderList = self.requestOrderList() - # 15:10:00 이후라면 모든 미체결 취소한다. - self.cancelOrderList(orderList) - - # 매도 가격을 가져온다. - result = self.getRealTime(stock['stock_code'], today, LAST_DATA[stock['stock_code']]) - final_price = result["close"][len(result["close"]) - 1] - - orderNum, sell_time, jango, sell_price = self.getSellingPrice(THIS_TIME, stock['stock_code'], final_price, without_loss=True) - # 로그 출력 - print("SELL", sell_time, stock['stock_code'], stock['stock_name'], final_price, str(orderNum), jango, sell_price) - - final_sell_check = True - """ - - time.sleep(3600) - THIS_TIME = datetime.now() - - return True - - def updteTodayStock(self, stock_code, today_str): - bsLine, data = self.labelChecker.makeCandidate(stock_code, today_str) - self.labelChecker.updateLabel(stock_code, bsLine, data, today_str) - return - - -if __name__ == "__main__": - - today = datetime.today() - - PROJECT_HOME = os.getcwd() - RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources") - - # KODEX 인버스 * 2 - stocks = [ - {"stock_code": "122630", "stock_name": "KODEX 레버리지"}, - {"stock_code": "305720", "stock_name": "KODEX 2차전지산업"}, - {"stock_code": "102780", "stock_name": "KODEX 삼성그룹"}, - {"stock_code": "139260", "stock_name": "TIGER 200 IT"}, - {"stock_code": "091180", "stock_name": "KODEX 자동차"}, - {"stock_code": "401470", "stock_name": "KODEX K-메타버스액티브"}, - {"stock_code": "329200", "stock_name": "TIGER 리츠부동산인프라"}, - {"stock_code": "091170", "stock_name": "KODEX 은행"}, - {"stock_code": "091160", "stock_name": "KODEX 반도체"}, - {"stock_code": "161510", "stock_name": "ARIRANG 고배당주"}, - {"stock_code": "228800", "stock_name": "TIGER 여행레저"}, - {"stock_code": "150460", "stock_name": "TIGER 중국소비테마"}, - {"stock_code": "143860", "stock_name": "TIGER 헬스케어"}, - {"stock_code": "228810", "stock_name": "TIGER 미디어컨텐츠"}, - {"stock_code": "139220", "stock_name": "TIGER 200 건설"}, - {"stock_code": "139280", "stock_name": "TIGER 경기방어"}, - {"stock_code": "322400", "stock_name": "HANARO e커머스"}, - {"stock_code": "157490", "stock_name": "TIGER 소프트웨어"}, - {"stock_code": "228790", "stock_name": "TIGER 화장품"}, - {"stock_code": "139230", "stock_name": "TIGER 200 중공업"}, - {"stock_code": "396500", "stock_name": "TIGER Fn반도체TOP10"}, - {"stock_code": "365000", "stock_name": "TIGER KRX인터넷K-뉴딜"}, - {"stock_code": "102970", "stock_name": "KODEX 증권"}, - {"stock_code": "117680", "stock_name": "KODEX 철강"}, - {"stock_code": "244580", "stock_name": "KODEX 바이오"}, - {"stock_code": "266360", "stock_name": "KODEX 미디어&엔터테인먼트"}, - {"stock_code": "375770", "stock_name": "KODEX 탄소효율그린뉴딜"}, - {"stock_code": "364990", "stock_name": "TIGER KRX게임K-뉴딜"}, - {"stock_code": "388420", "stock_name": "KBSTAR 비메모리반도체액티브"}, - {"stock_code": "117460", "stock_name": "KODEX 에너지화학"}, - {"stock_code": "300950", "stock_name": "KODEX 게임산업"}, - {"stock_code": "266410", "stock_name": "KODEX 필수소비재"}, - {"stock_code": "140700", "stock_name": "KODEX 보험"}, - {"stock_code": "139270", "stock_name": "TIGER 200 금융"}, - {"stock_code": "395160", "stock_name": "KODEX Fn시스템반도체"}, - {"stock_code": "140710", "stock_name": "KODEX 운송"}, - {"stock_code": "139240", "stock_name": "TIGER 200 철강소재"}, - {"stock_code": "395150", "stock_name": "KODEX Fn웹툰&드라마"}, - {"stock_code": "307510", "stock_name": "TIGER 의료기기"}, - {"stock_code": "315270", "stock_name": "TIGER 200커뮤니케이션서비스"}, - {"stock_code": "132030", "stock_name": "KODEX 골드선물(H)"}, - {"stock_code": "144600", "stock_name": "KODEX 은선물(H)"}, - {"stock_code": "261220", "stock_name": "KODEX WTI원유선물(H)"}, - {"stock_code": "271050", "stock_name": "KODEX WTI원유선물인버스(H)"}, - {"stock_code": "138910", "stock_name": "KODEX 구리선물(H)"} - ] - - hts = HTS_etf(RESOURCE_PATH) - hts.connect2DB("hts.db") - hts.connect2StockDB() - - today_str = today.strftime('%Y%m%d') - hts.buyRealTime(today_str, stocks, analyzed_day=1000) - - db_filename = os.path.join(RESOURCE_PATH, "hts.db") - hts.insertStockData(stocks, today) - - hts.disconnectStockDB() - hts.disconnect() - print ("done...") diff --git a/HTS_etf_short.py b/HTS_etf_short.py deleted file mode 100644 index 3da149d..0000000 --- a/HTS_etf_short.py +++ /dev/null @@ -1,358 +0,0 @@ -import time -import os -import math -import sqlite3 -from datetime import datetime, timedelta - -from hts.HTS import HTS -from hts.OrderType import OrderType - -from hts.BuySellChecker import BuySellChecker -from hts.OrderChecker import OrderChecker -from stock.util.LabelChecker import LabelChecker -from stock.util.TelegramBot import TelegramBot -from stock.analysis.StockStatus import StockStatus - -class HTS_etf (HTS): - - RESOURCE_PATH = None - stock_code = None - buy_count = None - orderChecker = None - buySellChecker = None - labelChecker = None - bot = None - stockStatus = None - - def __init__(self, RESOURCE_PATH): - super().__init__(RESOURCE_PATH) - - self.RESOURCE_PATH = RESOURCE_PATH - - self.orderChecker = OrderChecker(self.RESOURCE_PATH, "ETF") - self.buySellChecker = BuySellChecker() - self.labelChecker = LabelChecker(RESOURCE_PATH) - self.bot = TelegramBot() - self.stockStatus = StockStatus(RESOURCE_PATH) - - return - - def connect2StockDB(self): - - self.conn_stock = sqlite3.connect(os.path.join(self.RESOURCE_PATH, "resources/stock.db")) - self.cursor_stock = self.conn_stock.cursor() - - return - - def disconnectStockDB(self): - - self.cursor_stock.close() - self.conn_stock.close() - return - - def sellStocks(self, stock_code=None, bs_sell_price=None): - check = False - jangoDic = self.requstJango() - if jangoDic and len(jangoDic.keys()) > 0: - for code in jangoDic: - if stock_code is not None: - if code == "A"+stock_code and bs_sell_price is not None: - if jangoDic[code]['매도가능'] > 0: - if 2 < jangoDic[code]['평가손익']: - self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], bs_sell_price) - self.bot.post(code, jangoDic[code]['종목명'], "SELL", bs_sell_price, jangoDic[code]['매도가능']) - check = True - else: - continue - else: - if jangoDic[code]['매도가능'] > 0: - if 3 < jangoDic[code]['평가손익']: - # 3% 이상 시 수익 매도 - currentStock = self.currentStock(code[1:]) - self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], currentStock['close']) - self.bot.post(code, jangoDic[code]['종목명'], "SELL", currentStock['close'], jangoDic[code]['매도가능']) - check = True - return check - - - def getSellingPrice(self, log_time, stock_code, final_price, without_loss=False): - # final_price와 diff를 받으면, 해당 가격으로 그냥 매도한다는 의미 - # final_price와 diff가 None이면 장부가와 final 중 max로 팔겠다는 의미 - # final_price가 0이고 diff가 None이면 장부가로 팔겠다는 의미임 - orderNum = None - jangoDic = self.requstJango() - if jangoDic and len(jangoDic.keys()) > 0: - for code in jangoDic: - if jangoDic[code]['매도가능'] > 0: - if without_loss: - if jangoDic[code]['장부가']*0.07 < jangoDic[code]['장부가'] - final_price: - sell_price = jangoDic[code]['장부가'] - if code == "A" + stock_code: - orderNum = self.requestOrder(OrderType.sell, stock_code, jangoDic[code]['매도가능'], sell_price) - return orderNum, log_time.strftime('%Y%m%d %H%M%S'), jangoDic[code]['매도가능'], sell_price - else: - max_price = max(jangoDic[code]['장부가'], final_price) - sell_price = (int(max_price) - int(max_price) % 5) + 5 - if code == "A"+stock_code: - orderNum = self.requestOrder(OrderType.sell, stock_code, jangoDic[code]['매도가능'], sell_price) - return orderNum, log_time.strftime('%Y%m%d %H%M%S'), jangoDic[code]['매도가능'], sell_price - return orderNum, None, None, None - - - def makeTickData(self, data, mins=30): - result = {"check": set(), - "time": [], - "open": [], - "close": [], - "high": [], - "low": [], - "vol": [], - "label": []} - - for i in range(mins, len(data['time'])+1): - result["check"].add(data['time'][i-1]) - result["time"].append(data['time'][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["vol"].append(sum(data['vol'][i - mins: i])) - - return result - - def getStockType(self, stock_code, short=False): - slow_k, p_slow_k, slow_k_week, p_slow_k_week, slow_k_month, p_slow_k_month = -1, -1, -1, -1, -1, -1 - - self.cursor_stock.execute('select stochastic_slow_k, max(ymd) from stock_analysis where code=? group by 1 order by ymd desc',(stock_code,)) - items = self.cursor_stock.fetchall() - if items is not None and len(items) > 1: - for i, item in enumerate(items): - if i == 0: - slow_k = item[0] - elif i == 1: - p_slow_k = item[0] - else: - break - - self.cursor_stock.execute('select stochastic_slow_k, max(ymd) from stock_analysis_weekly where code=? group by 1 order by ymd desc', (stock_code, )) - items = self.cursor_stock.fetchall() - if items is not None and len(items) > 1: - for i, item in enumerate(items): - if i == 0: - slow_k_week = item[0] - elif i == 1: - p_slow_k_week = item[0] - else: - break - - self.cursor_stock.execute('select stochastic_slow_k, max(ymd) from stock_analysis_monthly where code=? group by 1 order by ymd desc',(stock_code,)) - items = self.cursor_stock.fetchall() - if items is not None and len(items) > 1: - for i, item in enumerate(items): - if i == 0: - slow_k_month = item[0] - elif i == 1: - p_slow_k_month = item[0] - else: - break - - if slow_k is None or p_slow_k is None: - slow_k , p_slow_k = -1, -1 - if slow_k_week is None or p_slow_k_week is None: - slow_k_week, p_slow_k_week = -1, -1 - if slow_k_month is None or p_slow_k_month is None: - slow_k_month, p_slow_k_month = -1, -1 - - - type_stock = {'day':1, 'week':10, 'month':100} - if short: - - if slow_k < 10: type_stock['day'] = 10 - if 10 < slow_k < 15: type_stock['day'] = 7.5 - if 15 < slow_k < 20: type_stock['day'] = 5 - if 20 < slow_k < 25: type_stock['day'] = 2.5 - - if slow_k_week < 10: type_stock['week'] = 100 - if 10 < slow_k_week < 15: type_stock['week'] = 75 - if 15 < slow_k_week < 20: type_stock['week'] = 50 - if 20 < slow_k_week < 25: type_stock['week'] = 25 - - if slow_k_month < 10: type_stock['month'] = 1000 - if 10 < slow_k_month < 15: type_stock['month'] = 750 - if 15 < slow_k_month < 20: type_stock['month'] = 500 - if 20 < slow_k_month < 25: type_stock['month'] = 250 - else: - - if slow_k > 90: type_stock['day'] = 10 - if 85 < slow_k < 90: type_stock['day'] = 7.5 - if 80 < slow_k < 85: type_stock['day'] = 5 - if 75 < slow_k < 80: type_stock['day'] = 2.5 - - if slow_k_week > 90: type_stock['week'] = 100 - if 85 < slow_k_week < 90: type_stock['week'] = 75 - if 80 < slow_k_week < 85: type_stock['week'] = 50 - if 75 < slow_k_week < 80: type_stock['week'] = 25 - - if slow_k_month > 90: type_stock['month'] = 1000 - if 85 < slow_k_month < 90: type_stock['month'] = 750 - if 80 < slow_k_month < 85: type_stock['month'] = 500 - if 75 < slow_k_month < 80: type_stock['month'] = 250 - - return type_stock - - def getBuyCount(self, bs_buy_price, kospi_type, stock_type): - - base_price = 10000 - log_base = 1.2 - p_k_m, p_k_w, p_k_d, p_s_m, p_s_w, p_s_d = 0.3, 0.2, 0.05, 0.25, 0.18, 0.02 - weight_1, weight_2, weight_3, weight_4, weight_5 = 0.5, 0.3, 0.14, 0.05, 0.01 - kospi_weight = weight_5 - if kospi_type['day'] == 10: kospi_weight = weight_1 - if kospi_type['day'] == 7.5: kospi_weight = weight_2 - if kospi_type['day'] == 5: kospi_weight = weight_3 - if kospi_type['day'] == 2.5: kospi_weight = weight_4 - stock_weight = weight_5 - if stock_type['day'] == 10: stock_weight = weight_1 - if stock_type['day'] == 7.5: stock_weight = weight_2 - if stock_type['day'] == 5: stock_weight = weight_3 - if stock_type['day'] == 2.5: stock_weight = weight_4 - - max_price = math.log( - kospi_weight * p_k_m * kospi_type['month'] + - kospi_weight * p_k_w * kospi_type['week'] + - kospi_weight * p_k_d * kospi_type['day'] + - stock_weight * p_s_m * stock_type['month'] + - stock_weight * p_s_w * stock_type['week'] + - stock_weight * p_s_d * stock_type['day'], log_base) * base_price - - buy_count = 0 - if max_price > 1: - buy_count = int(math.floor(max_price / bs_buy_price)) - - return buy_count - - def buyRealTime(self, today, stocks, analyzed_day=1000): - - print ("START...") - THIS_TIME = datetime.now() - kospi_type = self.getStockType("^KS11", short=False) - - LAST_DATA = {} - for stock in stocks: - LAST_DATA[stock['stock_code']] = self.getLastData(stock['stock_code'], today) - - while datetime.strptime(today + " 070000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 153100", '%Y%m%d %H%M%S'): - - if datetime.strptime(today + " 090000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 151500", '%Y%m%d %H%M%S'): - - # 매도를 체크한다. - # self.sellStocks() - - for idx, stock in enumerate(stocks): - - time.sleep(0.1) - - print("%5d: %8s, %-50s"%(idx, stock['stock_code'], stock['stock_name'])) - - try: - # 데이터를 가지고 온다. - data = self.getRealTime(stock['stock_code'], today, LAST_DATA[stock['stock_code']]) - except: - print("#ERROR:", stock['stock_code'], stock['stock_name']) - continue - - # 현재 매수가 - bs_buy_price = data["close"][len(data["close"]) - 1] - - # 미체결 기록을 가져와서 10분 이상 된 매수 주문을 취소 한다. - ORDER_LIST = self.requestOrderList() - orderListToCancel = self.orderChecker.cancel(today, "A" + stock['stock_code'], ORDER_LIST, mins=10) - if len(orderListToCancel) > 0: - self.cancelOrderList(orderListToCancel) - - if bs_buy_price > 1000: - - if not self.orderChecker.exist(today, "A" + stock['stock_code'], hours=5): - stock_type = self.getStockType(stock['stock_code'], short=True) - buy_count = self.getBuyCount(bs_buy_price, kospi_type, stock_type) - - if buy_count > 0: - - # 매수를 주문한다. - orderNum = self.requestOrder(OrderType.buy, stock['stock_code'], buy_count , bs_buy_price) - self.orderChecker.buy(today, "A" + stock['stock_code'], buy_count, bs_buy_price, orderNum) - - # bot에 메시지를 보냄 - self.bot.post(stock['stock_code'], stock['stock_name'], "BUY", bs_buy_price, buy_count) - - # 로그 출력 - print("BUY", THIS_TIME.strftime('%Y%m%d %H%M%S'), orderNum, stock['stock_code'], stock['stock_name'], bs_buy_price, buy_count) - - # 로그 출력 - print("TIMECHECK: %s, code: %s, name: %s, buy: %d, avg5: %.2f, avg30: %.2f, open: %d, high: %d, low: %d, slow_k: %.2f" % - (str(THIS_TIME), stock['stock_code'], stock['stock_name'], bs_buy_price, data["avg5"][0], data["avg30"][0], - data["open"][0], data["high"][0], data["low"][0], data["slow_k"][0])) - - """ - elif datetime.strptime(today + " 151530", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 151600", '%Y%m%d %H%M%S'): - # 3시 15분 30초부터 3시 16분 사이는 잔량을 매도한다. - - if not final_sell_check: - #### - # 손해 보지 않는 가격에 매도한다. - #### - - for stock in stocks: - # 주문 리스트를 가져온다. - orderList = self.requestOrderList() - # 15:10:00 이후라면 모든 미체결 취소한다. - self.cancelOrderList(orderList) - - # 매도 가격을 가져온다. - result = self.getRealTime(stock['stock_code'], today, LAST_DATA[stock['stock_code']]) - final_price = result["close"][len(result["close"]) - 1] - - orderNum, sell_time, jango, sell_price = self.getSellingPrice(THIS_TIME, stock['stock_code'], final_price, without_loss=True) - # 로그 출력 - print("SELL", sell_time, stock['stock_code'], stock['stock_name'], final_price, str(orderNum), jango, sell_price) - - final_sell_check = True - """ - - time.sleep(3600) - THIS_TIME = datetime.now() - - return True - - def updteTodayStock(self, stock_code, today_str): - bsLine, data = self.labelChecker.makeCandidate(stock_code, today_str) - self.labelChecker.updateLabel(stock_code, bsLine, data, today_str) - return - - -if __name__ == "__main__": - - today = datetime.today() - - PROJECT_HOME = os.getcwd() - RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources") - - # KODEX 인버스 * 2 - stocks = [ - {"stock_code": "252670", "stock_name": "KODEX 200선물인버스2X"} - ] - - hts = HTS_etf(RESOURCE_PATH) - hts.connect2DB("hts.db") - hts.connect2StockDB() - - today_str = today.strftime('%Y%m%d') - hts.buyRealTime(today_str, stocks, analyzed_day=1000) - - db_filename = os.path.join(RESOURCE_PATH, "hts.db") - hts.insertStockData(stocks, today) - - hts.disconnectStockDB() - hts.disconnect() - print ("done...") diff --git a/HTS_stocks.py b/HTS_stocks.py deleted file mode 100644 index 9aa3f25..0000000 --- a/HTS_stocks.py +++ /dev/null @@ -1,181 +0,0 @@ -import re -import os -import time -import psutil -import sqlite3 -from datetime import datetime, timedelta - -from hts.HTS import HTS -from hts.OrderType import OrderType - -from hts.BuySellChecker import BuySellChecker -from hts.OrderChecker import OrderChecker -from stock.util.TelegramBot import TelegramBot -from stock.analysis.StockStatus import StockStatus - -class HTS_Stocks (HTS): - - RESOURCE_PATH = None - orderChecker = None - buySellChecker = None - labelChecker = None - bot = None - stockStatus = None - analyzed_day = None - MAX_BUY_PRICE = None - - conn_stock = None - cursor_stock = None - - def __init__(self, RESOURCE_PATH): - super().__init__(RESOURCE_PATH) - self.bot = TelegramBot() - - self.RESOURCE_PATH = RESOURCE_PATH - self.stockStatus = StockStatus(RESOURCE_PATH) - - self.buySellChecker = BuySellChecker(RESOURCE_PATH) - self.orderChecker = OrderChecker(self.RESOURCE_PATH, "STOCK") - - self.analyzed_day = 120 - self.MAX_BUY_PRICE = 300000 - - return - - def connect2StockDB(self): - - self.conn_stock = sqlite3.connect(os.path.join(self.RESOURCE_PATH, "stock.db")) - self.cursor_stock = self.conn_stock.cursor() - - return - - def disconnectStockDB(self): - - self.cursor_stock.close() - self.conn_stock.close() - return - - def sellStocks(self, stock_code=None): - check = False - jangoDic = self.requstJango() - if jangoDic and len(jangoDic.keys()) > 0: - for code in jangoDic: - if stock_code is not None: - if code == "A" + stock_code: - if jangoDic[code]['매도가능'] > 0: - if 3.0 < jangoDic[code]['평가손익']: - self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], jangoDic[code]['현재가']) - self.bot.sendMsg("Profit {} ({}): {:.2f} ({:.2f}%)".format(jangoDic[code]['종목명'], jangoDic[code]['종목코드'], (jangoDic[code]['현재가']-jangoDic[code]['장부가'])*jangoDic[code]['잔고수량'], jangoDic[code]['평가손익'])) - check = True - else: - if 30.0 < jangoDic[code]['평가손익']: - self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], jangoDic[code]['현재가']) - self.bot.sendMsg("Profit {} ({}): {:.2f} ({:.2f}%)".format(jangoDic[code]['종목명'], jangoDic[code]['종목코드'], (jangoDic[code]['현재가']-jangoDic[code]['장부가'])*jangoDic[code]['잔고수량'], jangoDic[code]['평가손익'])) - check = True - return check - - def buyRealTime(self, today, n = 200): - print ("START...") - THIS_TIME = datetime.now() - - while datetime.strptime(today + " 070000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 153100", '%Y%m%d %H%M%S'): - THIS_TIME = datetime.now() - - # 1515 까지만 매수를 시도한다. - if datetime.strptime(today + " 090500", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 151500", '%Y%m%d %H%M%S'): - - today_stock = self.get_today_stock() - if len(today_stock) < 1: - self.sellStocks() - time.sleep(300) - continue - - for idx, stock in enumerate(today_stock): - stock_code = stock['code'] - filename = stock['filename'] - - time.sleep(0.1) - - stock = self.stockStatus.fetchLastData(self.cursor_stock, stock_code, n) - - self.getRealTime_DailyCheck(today, stock_code, stock) - data = self.stockStatus.analyze(stock, self.analyzed_day) - - - # 매도 - if not data['avg60'][-1] < data['avg20'][-1] < data['avg5'][-1]: - self.sellStocks(stock_code) - - # 매수 - bs_buy_price = data["close"][-1] - - if 150000 < bs_buy_price: - buy_count = 1 - else: - buy_count = 150000 // bs_buy_price - - # 매수를 주문한다. - orderNum = self.requestOrder(OrderType.buy, stock_code, buy_count, bs_buy_price) - self.orderChecker.buy(today, "A" + stock_code, buy_count, bs_buy_price, orderNum) - - # bot에 메시지를 보냄 - self.bot.sendMsg('BUY {} {} ({})'.format(stock_code, bs_buy_price, buy_count)) - - arr = os.path.splitext(filename) - os.rename(filename, arr[0]+'.[BUY]'+arr[1]) - - # 로그 출력 - print("BUY", THIS_TIME.strftime('%Y%m%d %H%M%S'), orderNum, stock_code, '', bs_buy_price, buy_count) - - if int(THIS_TIME.strftime("%M")) in (10, 40): - vm = psutil.virtual_memory() - vm_item = dict() - vm_item['free'] = vm.available // (1024 * 1024) - vm_item['idle'] = vm.available / vm.total * 100 - hts.bot.sendMsg("Alive... mem: {:.1f}".format(vm_item['idle'])) - - time.sleep(100) - - return - - def updteTodayStock(self, db_filename, stock_code, today_str): - bsLine, data = self.labelChecker.makeCandidate(stock_code, today_str) - self.labelChecker.updateLabel(db_filename, stock_code, bsLine, data, today_str) - return - - def get_today_stock(self): - today_stock = [] - path = os.path.join(self.RESOURCE_PATH, 'analysis', '종목선택') - file_list = os.listdir(path) - for filename in file_list: - # '20240130_2_daily_최적_타이밍_후보__1162_넥스틸_092790.html' - #pattern = '([0-9]+)_[1-9]_daily_최적_타이밍_후보__[0-9]+_([ㄱ-ㅎ가-힣a-zA-Z0-9]+)_([0-9]+)\.html' - pattern = '([0-9]+)_[1-9]_daily_final_candidate__[0-9]+_.*_([0-9]+)\.html' - info = re.search(pattern, filename) - if info is None: - continue - - date_str = datetime.strptime(info.group(1), "%Y%m%d").strftime("%Y%m%d") - if date_str == datetime.today().strftime("%Y%m%d") or date_str == (datetime.today() - timedelta(days=1)).strftime("%Y%m%d"): - stock = {'code': info.group(2), 'filename': os.path.join(path, filename)} - today_stock.append(stock) - - return today_stock - -if __name__ == "__main__": - today = datetime.today() - - PROJECT_HOME = os.getcwd() - RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources") - - hts = HTS_Stocks(RESOURCE_PATH) - hts.connect2DB("hts.db") - hts.connect2StockDB() - - today_str = today.strftime('%Y%m%d') - hts.buyRealTime(today_str) - - hts.disconnectStockDB() - hts.disconnect() - - print ("done...") diff --git a/JSDPattern.py b/JSDPattern.py new file mode 100644 index 0000000..95082a0 --- /dev/null +++ b/JSDPattern.py @@ -0,0 +1,274 @@ +# 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 pyupbit +import math +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 + +class JSDPattern: + RESOURCE_PATH = None + ichimokuCloud = None + scaler = None + + def __init__(self, RESOURCE_PATH=None): + if RESOURCE_PATH is None: + self.RESOURCE_PATH = os.path.join(os.getcwd(), "resources") + else: + self.RESOURCE_PATH = RESOURCE_PATH + + self.ichimokuCloud = IchimokuCloud() + 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'].iloc[i]) + data['close'].append(df['close'].iloc[i]) + data['high'].append(df['high'].iloc[i]) + data['low'].append(df['low'].iloc[i]) + data['volume'].append(df['volume'].iloc[i]) + + return data + + def getDBData(self, stock_code, day, mins, get_days=14): + + if mins == 3: + table = 'minute3' + elif mins == 5: + table = 'minute5' + elif mins == 10: + table = 'minute10' + elif mins == 20: + table = 'minute20' + elif mins == 30: + table = 'minute30' + elif mins == 60: + table = 'minute60' + elif mins == 200: + table = 'minute200' + elif mins == 1440: + table = 'daily' + else: + table = 'minutely' + + conn = sqlite3.connect(os.path.join(self.RESOURCE_PATH, 'coins.db')) + cursor = conn.cursor() + + result = {"ymd": [], "open": [], "close": [], "high": [], "low": [], "volume": [], "label": []} + 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, hms, open, high, low, close, volume FROM ' + table + ' WHERE (CODE=? or CODE=?) and (ymd=?) order by ymd, hms', (stock_code, stock_code.replace('KRW-', ''), this_day,)) + + db_result = cursor.fetchall() + for rows in db_result: + ymd = rows[0] # hts.날짜 + hms = rows[1] # hts.시간 + open = rows[2] # hts.시가 + high = rows[3] # hts.고가 + low = rows[4] # hts.저가 + close = rows[5] # hts.종가 + vol = rows[6] # hts.거래량 + + temp = datetime.strptime(str(ymd) + " " + hms, '%Y%m%d %H%M%S') + + result["ymd"].append(temp) + 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, mins=None, to=None, ymd=None, get_days=14): + result = None + + if ymd is not None and datetime.now() < datetime.strptime(ymd, '%Y%m%d'): + ymd = None + + if ymd is None: + if to is None: + if mins is None: + df = pyupbit.get_ohlcv(ticker=ticker['ticker_code']) + else: + if mins == 1440: + df = pyupbit.get_ohlcv(ticker=ticker['ticker_code'], interval='minute1', count=1) + else: + df = pyupbit.get_ohlcv(ticker=ticker['ticker_code'], interval='minute' + str(mins)) + else: + df = pyupbit.get_ohlcv(ticker=ticker['ticker_code'], interval='minute' + str(mins), to=to) + + if df is not None: + df["datetime"] = df.index + df = df[['open', 'high', 'low', 'close', 'volume']].astype(float) + + if mins is not None: + result = self.getDBData(ticker['ticker_code'], datetime.today().strftime('%Y%m%d'), mins=mins, get_days=get_days) + + data = self.append(df, result) + + else: + result = self.getDBData(ticker['ticker_code'], ymd, mins=mins, 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 not math.isnan(price1[i]) and price2[i] is not None and not math.isnan(price2[i]): + diff[i] = price1[i] - price2[i] + else: + diff[i] = np.nan + + 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 and not math.isnan(diff[i]): + 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] = np.nan + + return diff, diff_rate + + + def getDisparity_low_min(self, ticker, min='minutely'): + try: + self.conn = sqlite3.connect(os.path.join(self.RESOURCE_PATH, "coins.db")) + self.cursor = self.conn.cursor() + + self.cursor.execute("SELECT lowest_disparity FROM disparity WHERE (CODE=? or CODE=?) AND TYPE=?", (ticker['ticker_code'], ticker['ticker_code'].replace('KRW-', ''), min)) + db_result = self.cursor.fetchall() + self.cursor.close() + self.conn.close() + + if 0 < len(db_result): + return db_result[0][0] + + except: + return 0.90 + return 0.90 diff --git a/JSDPattern_daily.py b/JSDPattern_daily.py new file mode 100644 index 0000000..51c7103 --- /dev/null +++ b/JSDPattern_daily.py @@ -0,0 +1,769 @@ +# 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 numpy as np +from scipy.signal import argrelextrema +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 sklearn.preprocessing import MinMaxScaler + +from JSDPattern import JSDPattern + + +class JSDPattern_daily(JSDPattern): + scaler = None + + def __init__(self, RESOURCE_PATH=None): + super().__init__(RESOURCE_PATH) + self.scaler = MinMaxScaler() + return + + def get_Support_Resistance(self, df): + n = 5 + min_price = df.iloc[argrelextrema(df.values, np.less_equal, order=n)[0]] + max_price = df.iloc[argrelextrema(df.values, np.greater_equal, order=n)[0]] + return min_price.iloc[-1], max_price.iloc[-1] + + def analyze_raw(self, result, mins=1440): + result["volume"] = [result["volume"][i] if 0 < result["volume"][i] else 1 for i in range(len(result["volume"]))] + # 기본 캔들 정보 + open_df = pd.DataFrame(result["open"]) + close_df = pd.DataFrame(result["close"]) + high_df = pd.DataFrame(result["high"]) + low_df = pd.DataFrame(result["low"]) + volume_df = pd.DataFrame(result["volume"]) + + # 중복 제거 + ymd_df = pd.DataFrame(result["ymd"]) + data_dup = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1) + data_dup.columns = ["ymd", "open", "close", "high", "low", "volume"] + data_dup.index = pd.DatetimeIndex(result["ymd"]) + data_dup_sorted = data_dup.sort_index(ascending=True) + data_dup_sorted = data_dup_sorted.drop_duplicates() + + ymd_df = data_dup_sorted["ymd"] + open_df = data_dup_sorted["open"] + close_df = data_dup_sorted["close"] + high_df = data_dup_sorted["high"] + low_df = data_dup_sorted["low"] + volume_df = data_dup_sorted["volume"] + + min_price_list = [None for i in range(len(close_df)+51)] + max_price_list = [None for i in range(len(close_df)+51)] + for i in range(len(close_df)): + if 480 < i: + min_price_list[i], max_price_list[i] = self.get_Support_Resistance(close_df[i-120:i+1]) + + 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]) + + # 7일 신고가 + new_high_7 = [0 for c in range(6)] + [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 - 6:c + 1] and max(close[c - 6:c]) < close[c] else 0 for c in range(6, len(close))] + # 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))] + + # 7일 신저가 + new_low_7 = [0 for c in range(6)] + [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 - 6:c + 1] and close[c - 7] < min(close[c - 6:c + 1]) else 0 for c in range(6, 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)) + + # 이격도 + disparity_avg5_df = (close_df / close_df.ewm(span=5, min_periods=5, adjust=False).mean()) + disparity_avg10_df = (close_df / close_df.ewm(span=10, min_periods=10, adjust=False).mean()) + disparity_avg20_df = (close_df / close_df.ewm(span=20, min_periods=20, adjust=False).mean()) + disparity_avg60_df = (close_df / close_df.ewm(span=60, min_periods=60, adjust=False).mean()) + disparity_avg120_df = (close_df / close_df.ewm(span=120, min_periods=120, adjust=False).mean()) + disparity_avg240_df = (close_df / close_df.ewm(span=240, min_periods=240, adjust=False).mean()) + disparity_avg480_df = (close_df / close_df.ewm(span=480, min_periods=480, adjust=False).mean()) + disparity_avg720_df = (close_df / close_df.ewm(span=720, min_periods=720, adjust=False).mean()) + disparity_avg1440_df = (close_df / close_df.ewm(span=1440, min_periods=1440, adjust=False).mean()) + + disparity_480_loc = [0 for i in range(len(close))] + disparity_1440_loc = [0 for i in range(len(close))] + disparity_avg480_list = list(disparity_avg480_df.values.reshape(-1)) + disparity_avg1440_list = list(disparity_avg1440_df.values.reshape(-1)) + for i in range(0, len(close)): + if 2880 < i: + l = [d for d in disparity_avg480_list[i - 1440:i + 1]] + min_v = np.min(l) + max_v = np.max(l) + disparity_480_loc[i] = (disparity_avg480_list[i] - min_v) / (max_v - min_v) + l = [d for d in disparity_avg1440_list[i - 1440:i + 1]] + min_v = np.min(l) + max_v = np.max(l) + disparity_1440_loc[i] = (disparity_avg1440_list[i] - min_v) / (max_v - min_v) + + disparity_480_loc_df = pd.DataFrame(disparity_480_loc) + disparity_1440_loc_df = pd.DataFrame(disparity_1440_loc) + + 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_5_df, slowd_5_df = talib.STOCH(np_high, np_low, np_close, fastk_period=5, slowk_period=3, slowk_matype=0, slowd_period=3, slowd_matype=0) + slowk_10_df, slowd_10_df = talib.STOCH(np_high, np_low, np_close, fastk_period=10, slowk_period=6, slowk_matype=0, slowd_period=6, slowd_matype=0) + slowk_20_df, slowd_20_df = talib.STOCH(np_high, np_low, np_close, fastk_period=20, slowk_period=12, slowk_matype=0, slowd_period=12, slowd_matype=0) + slowk_60_df, slowd_60_df = talib.STOCH(np_high, np_low, np_close, fastk_period=60, slowk_period=37, slowk_matype=0, slowd_period=37, slowd_matype=0) + slowk_120_df, slowd_120_df = talib.STOCH(np_high, np_low, np_close, fastk_period=120, slowk_period=74, slowk_matype=0, slowd_period=74, slowd_matype=0) + slowk_240_df, slowd_240_df = talib.STOCH(np_high, np_low, np_close, fastk_period=240, slowk_period=148, slowk_matype=0, slowd_period=148, slowd_matype=0) + slowk_480_df, slowd_480_df = talib.STOCH(np_high, np_low, np_close, fastk_period=480, slowk_period=296, slowk_matype=0, slowd_period=296, 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 = 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 + + width_df = (upper_20 - lower_20) / middle_20 + width_min = np.min(width_df[0]) + width_max = np.max(width_df[0]) + bb_width_df = 100 * (width_df - width_min) / (width_max - width_min) + bb_pb_df = 100 * (close_df - lower_20) / (upper_20 - lower_20) + + 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)) + + disparity_avg5_list = list(disparity_avg5_df.values.reshape(-1)) + disparity_avg20_list = list(disparity_avg20_df.values.reshape(-1)) + disparity_avg60_list = list(disparity_avg60_df.values.reshape(-1)) + disparity_avg120_list = list(disparity_avg120_df.values.reshape(-1)) + disparity_avg240_list = list(disparity_avg240_df.values.reshape(-1)) + disparity_avg480_list = list(disparity_avg480_df.values.reshape(-1)) + disparity_avg720_list = list(disparity_avg720_df.values.reshape(-1)) + disparity_avg1440_list = list(disparity_avg1440_df.values.reshape(-1)) + + disparity_diff_20_5, disparity_diff_20_5_rate = self.getDiff_Rate(disparity_avg20_list, disparity_avg5_list, duration=20) + disparity_diff_60_20, disparity_diff_60_20_rate = self.getDiff_Rate(disparity_avg60_list, disparity_avg5_list, duration=60) + disparity_diff_120_20, disparity_diff_120_20_rate = self.getDiff_Rate(disparity_avg120_list, disparity_avg5_list, duration=120) + disparity_diff_240_20, disparity_diff_240_20_rate = self.getDiff_Rate(disparity_avg240_list, disparity_avg5_list, duration=240) + disparity_diff_480_20, disparity_diff_480_20_rate = self.getDiff_Rate(disparity_avg480_list, disparity_avg5_list, duration=480) + disparity_diff_720_20, disparity_diff_720_20_rate = self.getDiff_Rate(disparity_avg720_list, disparity_avg5_list, duration=720) + disparity_diff_1440_20, disparity_diff_1440_20_rate = self.getDiff_Rate(disparity_avg1440_list, disparity_avg5_list, duration=1440) + + 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(disparity_diff_20_5), pd.DataFrame(disparity_diff_20_5_rate), + pd.DataFrame(disparity_diff_60_20), pd.DataFrame(disparity_diff_60_20_rate), + pd.DataFrame(disparity_diff_120_20), pd.DataFrame(disparity_diff_120_20_rate), + pd.DataFrame(disparity_diff_240_20), pd.DataFrame(disparity_diff_240_20_rate), + pd.DataFrame(disparity_diff_480_20), pd.DataFrame(disparity_diff_480_20_rate), + pd.DataFrame(disparity_diff_720_20), pd.DataFrame(disparity_diff_720_20_rate), + pd.DataFrame(disparity_diff_1440_20), pd.DataFrame(disparity_diff_1440_20_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), + disparity_avg5_df, disparity_avg10_df, disparity_avg20_df, disparity_avg60_df, disparity_avg120_df, disparity_avg240_df, disparity_avg480_df, disparity_avg720_df, disparity_avg1440_df, disparity_480_loc_df, disparity_1440_loc_df, + + pd.DataFrame(upper_20), pd.DataFrame(lower_20), pd.DataFrame(middle_20), + bb_width_df, bb_pb_df, + + pd.DataFrame(new_high_7), pd.DataFrame(new_high_9), pd.DataFrame(new_high_26), pd.DataFrame(new_high_33), pd.DataFrame(new_high_52), + pd.DataFrame(new_low_7), pd.DataFrame(new_low_9), pd.DataFrame(new_low_26), pd.DataFrame(new_low_33), pd.DataFrame(new_low_52), + pd.DataFrame(slowk_5_df), pd.DataFrame(slowd_5_df), + pd.DataFrame(slowk_10_df), pd.DataFrame(slowd_10_df), + pd.DataFrame(slowk_20_df), pd.DataFrame(slowd_20_df), + pd.DataFrame(slowk_60_df), pd.DataFrame(slowd_60_df), + pd.DataFrame(slowk_120_df), pd.DataFrame(slowd_120_df), + pd.DataFrame(slowk_240_df), pd.DataFrame(slowd_240_df), + pd.DataFrame(slowk_480_df), pd.DataFrame(slowd_480_df), + + pd.DataFrame(min_price_list), pd.DataFrame(max_price_list) + ] + + data = pd.concat(df_list, axis=1) + column_names = [ + 'ymd', + 'open', 'close', 'high', 'low', 'volume', + 'changeLine', 'baseLine', 'laggingSpan', 'leadingSpan1', 'leadingSpan2', + + 'disparity_diff_20_5', 'disparity_diff_20_5_rate', + 'disparity_diff_60_20', 'disparity_diff_60_20_rate', + 'disparity_diff_120_20', 'disparity_diff_120_20_rate', + 'disparity_diff_240_20', 'disparity_diff_240_20_rate', + 'disparity_diff_480_20', 'disparity_diff_480_20_rate', + 'disparity_diff_720_20', 'disparity_diff_720_20_rate', + 'disparity_diff_1440_20', 'disparity_diff_1440_20_rate', + + 'loc_240_k', 'loc_240_d', 'loc_240_s', + + 'avg5', 'avg10', 'avg20', 'avg60', 'avg90', 'avg120', 'avg240', 'avg360', 'avg480', 'avg720', 'avg1440', 'avg2880', + 'disparity_avg5', 'disparity_avg10', 'disparity_avg20', 'disparity_avg60', 'disparity_avg120', 'disparity_avg240', 'disparity_avg480', 'disparity_avg720', 'disparity_avg1440', 'disparity_480_loc', 'disparity_1440_loc', + + 'upper_20', 'lower_20', 'middle_20', + 'bb_width', 'bb_pb', + + 'new_high_7', 'new_high_9', 'new_high_26', 'new_high_33', 'new_high_52', + 'new_low_7', 'new_low_9', 'new_low_26', 'new_low_33', 'new_low_52', + + 'slowk_5', 'slowd_5', + 'slowk_10', 'slowd_10', + 'slowk_20', 'slowd_20', + 'slowk_60', 'slowd_60', + 'slowk_120', 'slowd_120', + 'slowk_240', 'slowd_240', + 'slowk_480', 'slowd_480', + + 'min_price', 'max_price' + ] + data.columns = column_names + data.index = pd.DatetimeIndex(ymd) + + return data, current_index + + + def analyze_scale(self, result, mins=1440): + result["volume"] = [result["volume"][i] if 0 < result["volume"][i] else 1 for i in range(len(result["volume"]))] + # 기본 캔들 정보 + open_df = pd.DataFrame(result["open"]) + close_df = pd.DataFrame(result["close"]) + high_df = pd.DataFrame(result["high"]) + low_df = pd.DataFrame(result["low"]) + volume_df = pd.DataFrame(result["volume"]) + + # 중복 제거 + ymd_df = pd.DataFrame(result["ymd"]) + data_dup = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1) + data_dup.columns = ["ymd", "open", "close", "high", "low", "volume"] + data_dup.index = pd.DatetimeIndex(result["ymd"]) + data_dup_sorted = data_dup.sort_index(ascending=True) + data_dup_sorted = data_dup_sorted.drop_duplicates() + + ymd_df = data_dup_sorted["ymd"] + open_df = data_dup_sorted["open"] + close_df = data_dup_sorted["close"] + high_df = data_dup_sorted["high"] + low_df = data_dup_sorted["low"] + volume_df = data_dup_sorted["volume"] + + min_price_list = [None for i in range(len(close_df)+51)] + max_price_list = [None for i in range(len(close_df)+51)] + for i in range(len(close_df)): + if 480 < i: + min_price_list[i], max_price_list[i] = self.get_Support_Resistance(close_df[i-120:i+1]) + + ymd = ymd_df.tolist() + open = open_df.tolist() + close = close_df.tolist() + high = high_df.tolist() + low = low_df.tolist() + volume = volume_df.tolist() + + open_scaled = (self.scaler.fit_transform(pd.DataFrame(open))).reshape(1,-1)[0] + open_scaled = [0.0000000001 if c==0 else c for c in open_scaled] + close_scaled = (self.scaler.fit_transform(pd.DataFrame(close))).reshape(1,-1)[0] + close_scaled = [0.0000000001 if c == 0 else c for c in close_scaled] + high_scaled = (self.scaler.fit_transform(pd.DataFrame(high))).reshape(1,-1)[0] + high_scaled = [0.0000000001 if c == 0 else c for c in high_scaled] + low_scaled = (self.scaler.fit_transform(pd.DataFrame(low))).reshape(1,-1)[0] + low_scaled = [0.0000000001 if c == 0 else c for c in low_scaled] + volume_scaled = (self.scaler.fit_transform(pd.DataFrame(volume))).reshape(1, -1)[0] + volume_scaled = [0.0000000001 if c == 0 else c for c in volume_scaled] + + if len(close_scaled) < 5: + poly_5 = [0] * len(close_scaled) + else: + poly_5 = [0] * 4 + [np.polyfit(range(5), close_scaled[i - 4: i + 1], 1)[0] for i in range(4, len(close))] + if len(close_scaled) < 10: + poly_10 = [0] * len(close_scaled) + else: + poly_10 = [0] * 9 + [np.polyfit(range(10), close_scaled[i - 9: i + 1], 1)[0] for i in range(9, len(close))] + if len(close_scaled) < 20: + poly_20 = [0] * len(close_scaled) + else: + poly_20 = [0] * 19 + [np.polyfit(range(20), close_scaled[i - 19: i + 1], 1)[0] for i in range(19, len(close))] + if len(poly_5) < 60: + poly_60 = [0] * len(close_scaled) + else: + poly_60 = [0] * 59 + [np.polyfit(range(60), close_scaled[i - 59: i + 1], 1)[0] for i in range(59, len(close))] + if len(close_scaled) < 120: + poly_120 = [0] * len(close_scaled) + else: + poly_120 = [0] * 119 + [np.polyfit(range(120), close_scaled[i - 119: i + 1], 1)[0] for i in range(119, len(close))] + if len(close_scaled) < 240: + poly_240 = [0] * len(close_scaled) + else: + poly_240 = [0] * 239 + [np.polyfit(range(240), close_scaled[i - 239: i + 1], 1)[0] for i in range(239, len(close))] + if len(close_scaled) < 480: + poly_480 = [0] * len(close_scaled) + else: + poly_480 = [0] * 479 + [np.polyfit(range(480), close_scaled[i - 479: i + 1], 1)[0] for i in range(479, len(close))] + + # ichimokuCloud + df = pd.concat([pd.DataFrame(ymd), pd.DataFrame(open_scaled), pd.DataFrame(close_scaled), pd.DataFrame(high_scaled), pd.DataFrame(low_scaled), pd.DataFrame(volume_scaled)], 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]) + + # 7일 신고가 + new_high_7 = [0 for c in range(6)] + [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_scaled[c - 6:c + 1] and max(close_scaled[c - 6:c]) < close_scaled[c] else 0 for c in range(6, len(close_scaled))] + # 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_scaled[c - 8:c + 1] and max(close_scaled[c - 8:c]) < close_scaled[c] else 0 for c in range(8, len(close_scaled))] + # 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_scaled[c - 8:c + 1] and max(close_scaled[c - 25:c]) < close_scaled[c] else 0 for c in range(25, len(close_scaled))] + # 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_scaled[c - 8:c + 1] and max(close_scaled[c - 32:c]) < close_scaled[c] else 0 for c in range(32, len(close_scaled))] + # 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_scaled[c - 8:c + 1] and max(close_scaled[c - 51:c]) < close_scaled[c] else 0 for c in range(51, len(close_scaled))] + + # 7일 신저가 + new_low_7 = [0 for c in range(6)] + [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_scaled[c - 6:c + 1] and close_scaled[c - 7] < min(close_scaled[c - 6:c + 1]) else 0 for c in range(6, len(close_scaled))] + # 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_scaled[c - 8:c + 1] and close_scaled[c - 9] < min(close_scaled[c - 8:c + 1]) else 0 for c in range(8, len(close_scaled))] + # 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_scaled[c - 8:c + 1] and close_scaled[c - 26] < min(close_scaled[c - 25:c + 1]) else 0 for c in range(25, len(close_scaled))] + # 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_scaled[c - 8:c + 1] and close_scaled[c - 33] < min(close_scaled[c - 32:c + 1]) else 0 for c in range(32, len(close_scaled))] + # 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_scaled[c - 8:c + 1] and close_scaled[c - 52] < min(close_scaled[c - 51:c + 1]) else 0 for c in range(51, len(close_scaled))] + + # 이동 평균 + close_df = pd.DataFrame(close_scaled) + 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)) + + # 이격도 + disparity_avg5_df = (close_df / close_df.ewm(span=5, min_periods=5, adjust=False).mean()) + disparity_avg20_df = (close_df / close_df.ewm(span=20, min_periods=20, adjust=False).mean()) + disparity_avg60_df = (close_df / close_df.ewm(span=60, min_periods=60, adjust=False).mean()) + disparity_avg120_df = (close_df / close_df.ewm(span=120, min_periods=120, adjust=False).mean()) + disparity_avg240_df = (close_df / close_df.ewm(span=240, min_periods=240, adjust=False).mean()) + disparity_avg480_df = (close_df / close_df.ewm(span=480, min_periods=480, adjust=False).mean()) + disparity_avg1440_df = (close_df / close_df.ewm(span=1440, min_periods=1440, adjust=False).mean()) + + disparity_480_loc = [0 for i in range(len(close))] + disparity_1440_loc = [0 for i in range(len(close))] + disparity_avg480_list = list(disparity_avg480_df.values.reshape(-1)) + disparity_avg1440_list = list(disparity_avg1440_df.values.reshape(-1)) + for i in range(0, len(close)): + if 2880 < i: + l = [d for d in disparity_avg480_list[i - 1440:i + 1]] + min_v = np.min(l) + max_v = np.max(l) + disparity_480_loc[i] = (disparity_avg480_list[i] - min_v) / (max_v - min_v) + l = [d for d in disparity_avg1440_list[i - 1440:i + 1]] + min_v = np.min(l) + max_v = np.max(l) + disparity_1440_loc[i] = (disparity_avg1440_list[i] - min_v) / (max_v - min_v) + + disparity_480_loc_df = pd.DataFrame(disparity_480_loc) + disparity_1440_loc_df = pd.DataFrame(disparity_1440_loc) + + disparity_avg5_list = list(disparity_avg5_df.values.reshape(-1)) + disparity_avg20_list = list(disparity_avg20_df.values.reshape(-1)) + disparity_avg60_list = list(disparity_avg60_df.values.reshape(-1)) + disparity_avg120_list = list(disparity_avg120_df.values.reshape(-1)) + disparity_avg240_list = list(disparity_avg240_df.values.reshape(-1)) + disparity_avg480_list = list(disparity_avg480_df.values.reshape(-1)) + disparity_avg1440_list = list(disparity_avg1440_df.values.reshape(-1)) + + disparity_diff_20_5, disparity_diff_20_5_rate = self.getDiff_Rate(disparity_avg20_list, disparity_avg5_list, duration=20) + disparity_diff_60_20, disparity_diff_60_20_rate = self.getDiff_Rate(disparity_avg60_list, disparity_avg20_list, duration=60) + disparity_diff_120_20, disparity_diff_120_20_rate = self.getDiff_Rate(disparity_avg120_list, disparity_avg20_list, duration=120) + disparity_diff_240_20, disparity_diff_240_20_rate = self.getDiff_Rate(disparity_avg240_list, disparity_avg20_list, duration=240) + disparity_diff_480_20, disparity_diff_480_20_rate = self.getDiff_Rate(disparity_avg480_list, disparity_avg20_list, duration=480) + disparity_diff_1440_20, disparity_diff_1440_20_rate = self.getDiff_Rate(disparity_avg1440_list, disparity_avg20_list, duration=1440) + + np_high, np_low, np_close = np.array(high_scaled, dtype=np.float64), np.array(low_scaled, dtype=np.float64), np.array(close_scaled, dtype=np.float64) + slowk_5_df, slowd_5_df = talib.STOCH(np_high, np_low, np_close, fastk_period=5, slowk_period=3, slowk_matype=0, slowd_period=3, slowd_matype=0) + slowk_10_df, slowd_10_df = talib.STOCH(np_high, np_low, np_close, fastk_period=10, slowk_period=6, slowk_matype=0, slowd_period=6, slowd_matype=0) + slowk_20_df, slowd_20_df = talib.STOCH(np_high, np_low, np_close, fastk_period=20, slowk_period=12, slowk_matype=0, slowd_period=12, slowd_matype=0) + slowk_60_df, slowd_60_df = talib.STOCH(np_high, np_low, np_close, fastk_period=60, slowk_period=37, slowk_matype=0, slowd_period=37, slowd_matype=0) + slowk_120_df, slowd_120_df = talib.STOCH(np_high, np_low, np_close, fastk_period=120, slowk_period=74, slowk_matype=0, slowd_period=74, slowd_matype=0) + slowk_240_df, slowd_240_df = talib.STOCH(np_high, np_low, np_close, fastk_period=240, slowk_period=148, slowk_matype=0, slowd_period=148, slowd_matype=0) + slowk_480_df, slowd_480_df = talib.STOCH(np_high, np_low, np_close, fastk_period=480, slowk_period=296, slowk_matype=0, slowd_period=296, slowd_matype=0) + + # 최고/최저 위치 + loc_240 = [None for i in range(len(close))] + for i in range(240, len(close)): + min_v = np.min(close_scaled[i - 239:i + 1]) + max_v = np.max(close_scaled[i - 239:i + 1]) + if close[i] is not None: + loc_240[i] = ((close_scaled[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 = 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 + + width_df = (upper_20 - lower_20) / middle_20 + width_min = np.min(width_df[0]) + width_max = np.max(width_df[0]) + bb_width_df = 100 * (width_df - width_min) / (width_max - width_min) + bb_pb_df = 100 * (close_df - lower_20) / (upper_20 - lower_20) + + 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_scaled, 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_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_scaled, duration=duration) + changeLine_close_diff, changeLine_close_diff_rate = self.getDiff_Rate(changeLine, close_scaled, 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_scaled), pd.DataFrame(close_scaled), pd.DataFrame(high_scaled), pd.DataFrame(low_scaled), pd.DataFrame(volume_scaled), + 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_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_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), + disparity_avg5_df, disparity_avg20_df, disparity_avg60_df, disparity_avg120_df, disparity_avg240_df, disparity_avg480_df, disparity_avg1440_df, disparity_480_loc_df, disparity_1440_loc_df, + + pd.DataFrame(disparity_diff_20_5), pd.DataFrame(disparity_diff_20_5_rate), + pd.DataFrame(disparity_diff_60_20), pd.DataFrame(disparity_diff_60_20_rate), + pd.DataFrame(disparity_diff_120_20), pd.DataFrame(disparity_diff_120_20_rate), + pd.DataFrame(disparity_diff_240_20), pd.DataFrame(disparity_diff_240_20_rate), + pd.DataFrame(disparity_diff_480_20), pd.DataFrame(disparity_diff_480_20_rate), + pd.DataFrame(disparity_diff_1440_20), pd.DataFrame(disparity_diff_1440_20_rate), + + pd.DataFrame(upper_20), pd.DataFrame(lower_20), pd.DataFrame(middle_20), + bb_width_df, bb_pb_df, + + pd.DataFrame(new_high_7), pd.DataFrame(new_high_9), pd.DataFrame(new_high_26), pd.DataFrame(new_high_33), pd.DataFrame(new_high_52), + pd.DataFrame(new_low_7), pd.DataFrame(new_low_9), pd.DataFrame(new_low_26), pd.DataFrame(new_low_33), pd.DataFrame(new_low_52), + pd.DataFrame(slowk_5_df), pd.DataFrame(slowd_5_df), + pd.DataFrame(slowk_10_df), pd.DataFrame(slowd_10_df), + pd.DataFrame(slowk_20_df), pd.DataFrame(slowd_20_df), + pd.DataFrame(slowk_60_df), pd.DataFrame(slowd_60_df), + pd.DataFrame(slowk_120_df), pd.DataFrame(slowd_120_df), + pd.DataFrame(slowk_240_df), pd.DataFrame(slowd_240_df), + pd.DataFrame(slowk_480_df), pd.DataFrame(slowd_480_df), + + pd.DataFrame(min_price_list), pd.DataFrame(max_price_list), + pd.DataFrame(poly_5), pd.DataFrame(poly_10), pd.DataFrame(poly_20), pd.DataFrame(poly_60), pd.DataFrame(poly_120), pd.DataFrame(poly_240), pd.DataFrame(poly_480) + + ] + + 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_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_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', + 'disparity_avg5', 'disparity_avg20', 'disparity_avg60', 'disparity_avg120', 'disparity_avg240', 'disparity_avg480', 'disparity_avg1440', 'disparity_480_loc', 'disparity_1440_loc', + 'disparity_diff_20_5', 'disparity_diff_20_5_rate', + 'disparity_diff_60_20', 'disparity_diff_60_20_rate', + 'disparity_diff_120_20', 'disparity_diff_120_20_rate', + 'disparity_diff_240_20', 'disparity_diff_240_20_rate', + 'disparity_diff_480_20', 'disparity_diff_480_20_rate', + 'disparity_diff_1440_20', 'disparity_diff_1440_20_rate', + + 'upper_20', 'lower_20', 'middle_20', + 'bb_width', 'bb_pb', + + 'new_high_7', 'new_high_9', 'new_high_26', 'new_high_33', 'new_high_52', + 'new_low_7', 'new_low_9', 'new_low_26', 'new_low_33', 'new_low_52', + + 'slowk_5', 'slowd_5', + 'slowk_10', 'slowd_10', + 'slowk_20', 'slowd_20', + 'slowk_60', 'slowd_60', + 'slowk_120', 'slowd_120', + 'slowk_240', 'slowd_240', + 'slowk_480', 'slowd_480', + + + 'min_price', 'max_price', + 'poly_5', 'poly_10', 'poly_20', 'poly_60', 'poly_120', 'poly_240', 'poly_480' + ] + 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_scale, ci = self.analyze_scale(result) + data, ci = self.analyze_raw(result) + + return data, data_scale, ci diff --git a/JSDPattern_minutely.py b/JSDPattern_minutely.py new file mode 100644 index 0000000..c5ade1a --- /dev/null +++ b/JSDPattern_minutely.py @@ -0,0 +1,641 @@ +# 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 numpy as np +np.seterr(divide='ignore', invalid='ignore') +from scipy.signal import argrelextrema +# 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 sklearn.preprocessing import MinMaxScaler + +from JSDPattern import JSDPattern + +class JSDPattern_minutely (JSDPattern): + + scaler = None + + def __init__(self, RESOURCE_PATH=None): + super().__init__(RESOURCE_PATH) + self.scaler = MinMaxScaler() + + return + + def get_Support_Resistance(self, df): + n = 10 + support_df = df.iloc[argrelextrema(df.values, np.less_equal, order=n)[0]] + resistance_df = df.iloc[argrelextrema(df.values, np.greater_equal, order=n)[0]] + + support, resistance = np.zeros(len(df)), np.zeros(len(df)) + support[0], resistance[0] = df[0].iloc[0], df[0].iloc[0] + s_i, r_i = 0, 0 + for i in range(1, len(df)): + if s_i < len(support_df) and df.index[i] == support_df.index[s_i]: + support[i] = support_df[0].iloc[s_i] + s_i += 1 + else: + support[i] = support[i-1] + + if r_i < len(resistance_df) and df.index[i] == resistance_df.index[r_i]: + resistance[i] = resistance_df[0].iloc[r_i] + r_i += 1 + else: + resistance[i] = resistance[i-1] + + return support, resistance + + def analyze_raw(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() + + volume_rate = np.zeros(len(close)) + head_rate, body_rate, tail_rate = np.zeros(len(close)), np.zeros(len(close)), np.zeros(len(close)) + open_low_rate, open_high_rate, open_open_rate, open_close_rate = np.zeros(len(close)), np.zeros(len(close)), np.zeros(len(close)), np.zeros(len(close)) + close_low_rate, close_high_rate, close_open_rate, close_close_rate = np.zeros(len(close)), np.zeros(len(close)), np.zeros(len(close)), np.zeros(len(close)) + for i in range(len(close)): + length = high[i] - low[i] + + if 0 < length: + max_value = max(open[i], close[i]) + min_value = min(open[i], close[i]) + + head_rate[i] = (high[i] - max_value) / length + body_rate[i] = (max_value - min_value) / length + tail_rate[i] = (min_value - low[i]) / length + + if 0 < i: + if 0 < volume[i-1]: + volume_rate[i] = volume[i]/volume[i-1] + open_low_rate[i] = (low[i] - open[i-1])/open[i-1] + open_high_rate[i] = (high[i] - open[i-1])/open[i-1] + open_open_rate[i] = (open[i] - open[i-1])/open[i-1] + open_close_rate[i] = (close[i] - open[i-1])/open[i-1] + close_low_rate[i] = (low[i] - close[i-1])/close[i-1] + close_high_rate[i] = (high[i] - close[i-1])/close[i-1] + close_open_rate[i] = (open[i] - close[i-1])/close[i-1] + close_close_rate[i] = (close[i] - close[i-1])/close[i-1] + + + support, resistance = self.get_Support_Resistance(pd.DataFrame(close)) + + #z = np.polyfit(df['speed'], df['dist'], 1) # 기울기와 절편 확인 + #f = np.poly1d(z) # f(x): f함수 + if 5 < len(close): + poly_5 = [0] * 4 + [np.polyfit(range(5), close[i - 4: i + 1], 1)[0] for i in range(4, len(close))] + else: + poly_5 = [0] * len(close) + if 10 < len(close): + poly_10 = [0] * 9 + [np.polyfit(range(10), close[i - 9: i + 1], 1)[0] for i in range(9, len(close))] + else: + poly_10 = [0] * len(close) + if 20 < len(close): + poly_20 = [0] * 19 + [np.polyfit(range(20), close[i - 19: i + 1], 1)[0] for i in range(19, len(close))] + else: + poly_20 = [0] * len(close) + if 60 < len(close): + poly_60 = [0] * 59 + [np.polyfit(range(60), close[i - 59: i + 1], 1)[0] for i in range(59, len(close))] + else: + poly_60 = [0] * len(close) + if 120 < len(close): + poly_120 = [0] * 119 + [np.polyfit(range(120), close[i - 119: i + 1], 1)[0] for i in range(119, len(close))] + else: + poly_120 = [0] * len(close) + if 240 < len(close): + poly_240 = [0] * 239 + [np.polyfit(range(240), close[i - 239: i + 1], 1)[0] for i in range(239, len(close))] + else: + poly_240 = [0] * len(close) + if 480 < len(close): + poly_480 = [0] * 479 + [np.polyfit(range(480), close[i - 479: i + 1], 1)[0] for i in range(479, len(close))] + else: + poly_480 = [0] * len(close) + if 720 < len(close): + poly_720 = [0] * 719 + [np.polyfit(range(720), close[i - 719: i + 1], 1)[0] for i in range(719, len(close))] + else: + poly_720 = [0] * len(close) + if 1440 < len(close): + poly_1440 = [0] * 1439 + [np.polyfit(range(1440), close[i - 1439: i + 1], 1)[0] for i in range(1439, len(close))] + else: + poly_1440 = [0] * len(close) + + # 7일 신고가 + new_high_7 = [0 for c in range(6)] + [1 if (close[c - 1] is not None and close[c] is not None and close[c - 1] < close[c]) and None not in close[c - 6:c + 1] and max(close[c - 6:c]) < close[c] else 0 for c in range(6, len(close))] + # 9일 신고가 + new_high_9 = [0 for c in range(8)] + [1 if (close[c - 1] is not None and close[c] is not None and close[c - 1] < close[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 (close[c - 1] is not None and close[c] is not None and close[c - 1] < close[c]) and None not in close[c - 25:c + 1] and max(close[c - 25:c]) < close[c] else 0 for c in range(25, len(close))] + + # 7일 신저가 + new_low_7 = [0 for c in range(6)] + [1 if (close[c - 1] is not None and close[c] is not None and close[c - 1] < close[c]) and None not in close[c - 6:c + 1] and close[c - 6] < min(close[c - 6:c + 1]) else 0 for c in range(6, len(close))] + # 9일 신저가 + new_low_9 = [0 for c in range(8)] + [1 if (close[c - 1] is not None and close[c] is not None and close[c - 1] < close[c]) and None not in close[c - 8:c + 1] and close[c - 8] < 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 (close[c - 1] is not None and close[c] is not None and close[c - 1] < close[c]) and None not in close[c - 25:c + 1] and close[c - 25] < min(close[c - 25:c + 1]) else 0 for c in range(25, len(close))] + + high_th = [0] + for i in range(1, len(close)): + count = 0 + for c in range(i - 1, i - 30, -1): + if c < 0: + break + if close[i] < close[c]: + break + else: + count += 1 + high_th.append(count) + + # 이동 평균 + close_df = pd.DataFrame(close) + + avg5_df = close_df.ewm(5).mean() + avg10_df = close_df.ewm(10).mean() + avg20_df = close_df.ewm(20).mean() + avg60_df = close_df.ewm(60).mean() + avg120_df = close_df.ewm(120).mean() + avg240_df = close_df.ewm(240).mean() + avg480_df = close_df.ewm(480).mean() + avg720_df = close_df.ewm(720).mean() + avg1440_df = close_df.ewm(1440).mean() + + # 이격도 + disparity_avg5_df = (close_df / close_df.ewm(span=5, min_periods=5, adjust=False).mean()) + disparity_avg5_df = disparity_avg5_df.replace({None: np.nan}) + disparity_avg20_df = (close_df / close_df.ewm(span=20, min_periods=20, adjust=False).mean()) + disparity_avg20_df = disparity_avg20_df.replace({None: np.nan}) + disparity_avg60_df = (close_df / close_df.ewm(span=60, min_periods=60, adjust=False).mean()) + disparity_avg60_df = disparity_avg60_df.replace({None: np.nan}) + disparity_avg120_df = (close_df / close_df.ewm(span=120, min_periods=120, adjust=False).mean()) + disparity_avg120_df = disparity_avg120_df.replace({None: np.nan}) + disparity_avg240_df = (close_df / close_df.ewm(span=240, min_periods=240, adjust=False).mean()) + disparity_avg240_df = disparity_avg240_df.replace({None: np.nan}) + disparity_avg480_df = (close_df / close_df.ewm(span=480, min_periods=480, adjust=False).mean()) + disparity_avg480_df = disparity_avg480_df.replace({None: np.nan}) + disparity_avg720_df = (close_df / close_df.ewm(span=720, min_periods=720, adjust=False).mean()) + disparity_avg720_df = disparity_avg720_df.replace({None: np.nan}) + disparity_avg1440_df = (close_df / close_df.ewm(span=1440, min_periods=1440, adjust=False).mean()) + disparity_avg1440_df = disparity_avg1440_df.replace({None: np.nan}) + disparity_avg2880_df = (close_df / close_df.ewm(span=2880, min_periods=2880, adjust=False).mean()) + disparity_avg2880_df = disparity_avg2880_df.replace({None: np.nan}) + + + """""" + 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 + + width_df = (upper_20 - lower_20) / middle_20 + width_min = np.min(width_df[0]) + width_max = np.max(width_df[0]) + bb_width_df = 100 * (width_df - width_min) / (width_max - width_min) + bb_pb_df = 100 * (close_df - lower_20) / (upper_20 - lower_20) + + 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)) + + 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_5_df, slowd_5_df = talib.STOCH(np_high, np_low, np_close, fastk_period=5, slowk_period=3, slowk_matype=0, slowd_period=3, slowd_matype=0) + slowk_10_df, slowd_10_df = talib.STOCH(np_high, np_low, np_close, fastk_period=10, slowk_period=6, slowk_matype=0, slowd_period=6, slowd_matype=0) + slowk_20_df, slowd_20_df = talib.STOCH(np_high, np_low, np_close, fastk_period=20, slowk_period=12, slowk_matype=0, slowd_period=12, slowd_matype=0) + slowk_60_df, slowd_60_df = talib.STOCH(np_high, np_low, np_close, fastk_period=60, slowk_period=37, slowk_matype=0, slowd_period=37, slowd_matype=0) + slowk_120_df, slowd_120_df = talib.STOCH(np_high, np_low, np_close, fastk_period=120, slowk_period=74, slowk_matype=0, slowd_period=74, slowd_matype=0) + slowk_240_df, slowd_240_df = talib.STOCH(np_high, np_low, np_close, fastk_period=240, slowk_period=148, slowk_matype=0, slowd_period=148, slowd_matype=0) + slowk_480_df, slowd_480_df = talib.STOCH(np_high, np_low, np_close, fastk_period=480, slowk_period=296, slowk_matype=0, slowd_period=296, slowd_matype=0) + slowk_720_df, slowd_720_df = talib.STOCH(np_high, np_low, np_close, fastk_period=720, slowk_period=445, slowk_matype=0, slowd_period=445, slowd_matype=0) + slowk_1440_df, slowd_1440_df = talib.STOCH(np_high, np_low, np_close, fastk_period=1440, slowk_period=890, slowk_matype=0, slowd_period=890, slowd_matype=0) + willr = talib.WILLR(np_high, np_low, np_close, timeperiod=11) + 100 + rsi = talib.RSI(np_close, timeperiod=9) + rsi_720 = talib.RSI(np_close, timeperiod=720) + rsi_1440 = talib.RSI(np_close, timeperiod=1440) + macd, macds, macdo = talib.MACD(np_close, fastperiod=24, slowperiod=52, signalperiod=18) + macd_720, macds_720, macdo_720 = talib.MACD(np_close, fastperiod=332, slowperiod=720, signalperiod=250) + macd_1440, macds_1440, macdo_1440 = talib.MACD(np_close, fastperiod=665, slowperiod=1440, signalperiod=498) + + """ + """ + + df_list = [ + pd.DataFrame(ymd), + pd.DataFrame(open), pd.DataFrame(close), pd.DataFrame(high), pd.DataFrame(low), pd.DataFrame(volume), + pd.DataFrame(volume_rate), pd.DataFrame(head_rate), pd.DataFrame(body_rate), pd.DataFrame(tail_rate), + pd.DataFrame(open_low_rate), pd.DataFrame(open_high_rate), pd.DataFrame(open_open_rate), pd.DataFrame(open_close_rate), pd.DataFrame(close_low_rate), pd.DataFrame(close_high_rate), pd.DataFrame(close_open_rate), pd.DataFrame(close_close_rate), + + pd.DataFrame(list(support)), pd.DataFrame(list(resistance)), + pd.DataFrame(poly_5), pd.DataFrame(poly_10), pd.DataFrame(poly_20), pd.DataFrame(poly_60), pd.DataFrame(poly_120), pd.DataFrame(poly_240), pd.DataFrame(poly_480), pd.DataFrame(poly_720), pd.DataFrame(poly_1440), + + avg5_df, avg10_df, avg20_df, avg60_df, avg120_df, avg240_df, avg480_df, avg720_df, avg1440_df, + disparity_avg5_df, disparity_avg20_df, disparity_avg60_df, disparity_avg120_df, disparity_avg240_df, disparity_avg480_df, disparity_avg720_df, disparity_avg1440_df, disparity_avg2880_df, + + pd.DataFrame(new_high_7), pd.DataFrame(new_high_9), pd.DataFrame(new_high_26), pd.DataFrame(new_low_7), pd.DataFrame(new_low_9), pd.DataFrame(new_low_26), pd.DataFrame(high_th), + pd.DataFrame(upper_20), pd.DataFrame(lower_20), pd.DataFrame(middle_20), bb_width_df, bb_pb_df, pd.DataFrame(willr), + pd.DataFrame(slowk_5_df), pd.DataFrame(slowd_5_df), + pd.DataFrame(slowk_10_df), pd.DataFrame(slowd_10_df), + pd.DataFrame(slowk_20_df), pd.DataFrame(slowd_20_df), + pd.DataFrame(slowk_60_df), pd.DataFrame(slowd_60_df), + pd.DataFrame(slowk_120_df), pd.DataFrame(slowd_120_df), + pd.DataFrame(slowk_240_df), pd.DataFrame(slowd_240_df), + pd.DataFrame(slowk_480_df), pd.DataFrame(slowd_480_df), + pd.DataFrame(slowk_720_df), pd.DataFrame(slowd_720_df), + pd.DataFrame(slowk_1440_df), pd.DataFrame(slowd_1440_df), + pd.DataFrame(rsi), pd.DataFrame(rsi_720), pd.DataFrame(rsi_1440), + pd.DataFrame(macd), pd.DataFrame(macds), pd.DataFrame(macdo), + pd.DataFrame(macd_720), pd.DataFrame(macds_720), pd.DataFrame(macdo_720), + pd.DataFrame(macd_1440), pd.DataFrame(macds_1440), pd.DataFrame(macdo_1440), + + pd.DataFrame(open), pd.DataFrame(close), pd.DataFrame(high), pd.DataFrame(low), pd.DataFrame(volume), + + ] + + data = pd.concat(df_list, axis=1) + column_names = [ + 'ymd', + 'open', 'close', 'high', 'low', 'volume', + 'volume_rate', 'head_rate', 'body_rate', 'tail_rate', + 'open_low_rate', 'open_high_rate', 'open_open_rate', 'open_close_rate', 'close_low_rate', 'close_high_rate', 'close_open_rate', 'close_close_rate', + 'support', 'resistance', + 'poly_5', 'poly_10', 'poly_20', 'poly_60', 'poly_120', 'poly_240', 'poly_480', 'poly_720', 'poly_1440', + + 'avg5', 'avg10', 'avg20', 'avg60', 'avg120', 'avg240', 'avg480', 'avg720', 'avg1440', + 'disparity_avg5', 'disparity_avg20', 'disparity_avg60', 'disparity_avg120', 'disparity_avg240', 'disparity_avg480', 'disparity_avg720', 'disparity_avg1440', 'disparity_avg2880', + + 'new_high_7', 'new_high_9', 'new_high_26', 'new_low_7', 'new_low_9', 'new_low_26', 'high_th', + 'upper_20', 'lower_20', 'middle_20', 'bb_width', 'bb_pb', 'willr', + 'slowk_5', 'slowd_5', + 'slowk_10', 'slowd_10', + 'slowk_20', 'slowd_20', + 'slowk_60', 'slowd_60', + 'slowk_120', 'slowd_120', + 'slowk_240', 'slowd_240', + 'slowk_480', 'slowd_480', + 'slowk_720', 'slowd_720', + 'slowk_1440', 'slowd_1440', + 'rsi', 'rsi_720', 'rsi_1440', + 'macd', 'macds', 'macdo', + 'macd_720', 'macds_720', 'macdo_720', + 'macd_1440', 'macds_1440', 'macdo_1440', + + 'open_raw', 'close_raw', 'high_raw', 'low_raw', 'volume_raw' + ] + data.columns = column_names + data.index = pd.DatetimeIndex(ymd) + #data = data.dropna(axis=0) + return data, len(data) + + def analyze_scale(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() + + open_scaled = (self.scaler.fit_transform(pd.DataFrame(open))).reshape(1,-1)[0] + open_scaled = [0.0000000001 if c==0 else c for c in open_scaled] + close_scaled = (self.scaler.fit_transform(pd.DataFrame(close))).reshape(1,-1)[0] + close_scaled = [0.0000000001 if c == 0 else c for c in close_scaled] + high_scaled = (self.scaler.fit_transform(pd.DataFrame(high))).reshape(1,-1)[0] + high_scaled = [0.0000000001 if c == 0 else c for c in high_scaled] + low_scaled = (self.scaler.fit_transform(pd.DataFrame(low))).reshape(1,-1)[0] + low_scaled = [0.0000000001 if c == 0 else c for c in low_scaled] + volume_scaled = (self.scaler.fit_transform(pd.DataFrame(volume))).reshape(1, -1)[0] + volume_scaled = [0.0000000001 if c == 0 else c for c in volume_scaled] + + volume_rate = np.zeros(len(close)) + head_rate, body_rate, tail_rate = np.zeros(len(close)), np.zeros(len(close)), np.zeros(len(close)) + open_low_rate, open_high_rate, open_open_rate, open_close_rate = np.zeros(len(close)), np.zeros(len(close)), np.zeros(len(close)), np.zeros(len(close)) + close_low_rate, close_high_rate, close_open_rate, close_close_rate = np.zeros(len(close)), np.zeros(len(close)), np.zeros(len(close)), np.zeros(len(close)) + for i in range(len(close)): + length = high_scaled[i] - low_scaled[i] + + if 0 < length: + max_value = max(open_scaled[i], close_scaled[i]) + min_value = min(open_scaled[i], close_scaled[i]) + + head_rate[i] = (high_scaled[i] - max_value) / length + body_rate[i] = (max_value - min_value) / length + tail_rate[i] = (min_value - low_scaled[i]) / length + + if 0 < i: + if 0 < volume[i-1]: + volume_rate[i] = volume_scaled[i]/volume_scaled[i-1] + open_low_rate[i] = (low_scaled[i] - open_scaled[i-1])/open_scaled[i-1] + open_high_rate[i] = (high_scaled[i] - open_scaled[i-1])/open_scaled[i-1] + open_open_rate[i] = (open_scaled[i] - open_scaled[i-1])/open_scaled[i-1] + open_close_rate[i] = (close_scaled[i] - open_scaled[i-1])/open_scaled[i-1] + close_low_rate[i] = (low_scaled[i] - close_scaled[i-1])/close_scaled[i-1] + close_high_rate[i] = (high_scaled[i] - close_scaled[i-1])/close_scaled[i-1] + close_open_rate[i] = (open_scaled[i] - close_scaled[i-1])/close_scaled[i-1] + close_close_rate[i] = (close_scaled[i] - close_scaled[i-1])/close_scaled[i-1] + + + support, resistance = self.get_Support_Resistance(pd.DataFrame(close_scaled)) + + #z = np.polyfit(df['speed'], df['dist'], 1) # 기울기와 절편 확인 + #f = np.poly1d(z) # f(x): f함수 + if 5 < len(close): + poly_5 = [0] * 4 + [np.polyfit(range(5), close[i - 4: i + 1], 1)[0] for i in range(4, len(close))] + else: + poly_5 = [0] * len(close) + if 10 < len(close): + poly_10 = [0] * 9 + [np.polyfit(range(10), close[i - 9: i + 1], 1)[0] for i in range(9, len(close))] + else: + poly_10 = [0] * len(close) + if 20 < len(close): + poly_20 = [0] * 19 + [np.polyfit(range(20), close[i - 19: i + 1], 1)[0] for i in range(19, len(close))] + else: + poly_20 = [0] * len(close) + if 60 < len(close): + poly_60 = [0] * 59 + [np.polyfit(range(60), close[i - 59: i + 1], 1)[0] for i in range(59, len(close))] + else: + poly_60 = [0] * len(close) + if 120 < len(close): + poly_120 = [0] * 119 + [np.polyfit(range(120), close[i - 119: i + 1], 1)[0] for i in range(119, len(close))] + else: + poly_120 = [0] * len(close) + if 240 < len(close): + poly_240 = [0] * 239 + [np.polyfit(range(240), close[i - 239: i + 1], 1)[0] for i in range(239, len(close))] + else: + poly_240 = [0] * len(close) + if 480 < len(close): + poly_480 = [0] * 479 + [np.polyfit(range(480), close[i - 479: i + 1], 1)[0] for i in range(479, len(close))] + else: + poly_480 = [0] * len(close) + if 720 < len(close): + poly_720 = [0] * 719 + [np.polyfit(range(720), close[i - 719: i + 1], 1)[0] for i in range(719, len(close))] + else: + poly_720 = [0] * len(close) + if 1440 < len(close): + poly_1440 = [0] * 1439 + [np.polyfit(range(1440), close[i - 1439: i + 1], 1)[0] for i in range(1439, len(close))] + else: + poly_1440 = [0] * len(close) + + # 7일 신고가 + new_high_7 = [0 for c in range(6)] + [1 if (close_scaled[c - 1] is not None and close_scaled[c] is not None and close_scaled[c - 1] < close_scaled[c]) and None not in close_scaled[c - 6:c + 1] and max(close_scaled[c - 6:c]) < close_scaled[c] else 0 for c in range(6, len(close_scaled))] + # 9일 신고가 + new_high_9 = [0 for c in range(8)] + [1 if (close_scaled[c - 1] is not None and close_scaled[c] is not None and close_scaled[c - 1] < close_scaled[c]) and None not in close_scaled[c - 8:c + 1] and max(close_scaled[c - 8:c]) < close_scaled[c] else 0 for c in range(8, len(close_scaled))] + # 26일 신고가 + new_high_26 = [0 for c in range(25)] + [1 if (close_scaled[c - 1] is not None and close_scaled[c] is not None and close_scaled[c - 1] < close_scaled[c]) and None not in close_scaled[c - 25:c + 1] and max(close_scaled[c - 25:c]) < close_scaled[c] else 0 for c in range(25, len(close_scaled))] + + # 7일 신저가 + new_low_7 = [0 for c in range(6)] + [1 if (close_scaled[c - 1] is not None and close_scaled[c] is not None and close_scaled[c - 1] < close_scaled[c]) and None not in close_scaled[c - 6:c + 1] and close_scaled[c - 6] < min(close_scaled[c - 6:c + 1]) else 0 for c in range(6, len(close_scaled))] + # 9일 신저가 + new_low_9 = [0 for c in range(8)] + [1 if (close_scaled[c - 1] is not None and close_scaled[c] is not None and close_scaled[c - 1] < close_scaled[c]) and None not in close_scaled[c - 8:c + 1] and close_scaled[c - 8] < min(close_scaled[c - 8:c + 1]) else 0 for c in range(8, len(close_scaled))] + # 26일 신저가 + new_low_26 = [0 for c in range(25)] + [1 if (close_scaled[c - 1] is not None and close_scaled[c] is not None and close_scaled[c - 1] < close_scaled[c]) and None not in close_scaled[c - 25:c + 1] and close_scaled[c - 25] < min(close_scaled[c - 25:c + 1]) else 0 for c in range(25, len(close_scaled))] + + high_th = [0] + for i in range(1, len(close_scaled)): + count = 0 + for c in range(i-1,i-30,-1): + if c < 0: + break + if close_scaled[i] < close_scaled[c]: + break + else: + count += 1 + high_th.append(count) + + # 이동 평균 + close_df = pd.DataFrame(close_scaled) + + avg5_df = close_df.ewm(5).mean() + avg10_df = close_df.ewm(10).mean() + avg20_df = close_df.ewm(20).mean() + avg60_df = close_df.ewm(60).mean() + avg120_df = close_df.ewm(120).mean() + avg240_df = close_df.ewm(240).mean() + avg480_df = close_df.ewm(480).mean() + avg720_df = close_df.ewm(720).mean() + avg1440_df = close_df.ewm(1440).mean() + + # 이격도 + disparity_avg5_df = (close_df / close_df.ewm(span=5, min_periods=5, adjust=False).mean()) + disparity_avg5_df = disparity_avg5_df.replace({None: np.nan}) + disparity_avg20_df = (close_df / close_df.ewm(span=20, min_periods=20, adjust=False).mean()) + disparity_avg20_df = disparity_avg20_df.replace({None: np.nan}) + disparity_avg60_df = (close_df / close_df.ewm(span=60, min_periods=60, adjust=False).mean()) + disparity_avg60_df = disparity_avg60_df.replace({None: np.nan}) + disparity_avg120_df = (close_df / close_df.ewm(span=120, min_periods=120, adjust=False).mean()) + disparity_avg120_df = disparity_avg120_df.replace({None: np.nan}) + disparity_avg240_df = (close_df / close_df.ewm(span=240, min_periods=240, adjust=False).mean()) + disparity_avg240_df = disparity_avg240_df.replace({None: np.nan}) + disparity_avg480_df = (close_df / close_df.ewm(span=480, min_periods=480, adjust=False).mean()) + disparity_avg480_df = disparity_avg480_df.replace({None: np.nan}) + disparity_avg720_df = (close_df / close_df.ewm(span=720, min_periods=720, adjust=False).mean()) + disparity_avg720_df = disparity_avg720_df.replace({None: np.nan}) + disparity_avg1440_df = (close_df / close_df.ewm(span=1440, min_periods=1440, adjust=False).mean()) + disparity_avg1440_df = disparity_avg1440_df.replace({None: np.nan}) + disparity_avg2880_df = (close_df / close_df.ewm(span=2880, min_periods=2880, adjust=False).mean()) + disparity_avg2880_df = disparity_avg2880_df.replace({None: np.nan}) + + disparity_avg5_list = list(disparity_avg5_df.values.reshape(-1)) + disparity_avg20_list = list(disparity_avg20_df.values.reshape(-1)) + disparity_avg60_list = list(disparity_avg60_df.values.reshape(-1)) + disparity_avg120_list = list(disparity_avg120_df.values.reshape(-1)) + disparity_avg240_list = list(disparity_avg240_df.values.reshape(-1)) + disparity_avg480_list = list(disparity_avg480_df.values.reshape(-1)) + disparity_avg720_list = list(disparity_avg720_df.values.reshape(-1)) + disparity_avg1440_list = list(disparity_avg1440_df.values.reshape(-1)) + + disparity_diff_20_5, disparity_diff_20_5_rate = self.getDiff_Rate(disparity_avg20_list, disparity_avg5_list, duration=20) + disparity_diff_60_20, disparity_diff_60_20_rate = self.getDiff_Rate(disparity_avg60_list, disparity_avg20_list, duration=60) + disparity_diff_120_20, disparity_diff_120_20_rate = self.getDiff_Rate(disparity_avg120_list, disparity_avg20_list, duration=120) + disparity_diff_240_20, disparity_diff_240_20_rate = self.getDiff_Rate(disparity_avg240_list, disparity_avg20_list, duration=240) + disparity_diff_480_20, disparity_diff_480_20_rate = self.getDiff_Rate(disparity_avg480_list, disparity_avg20_list, duration=480) + disparity_diff_720_20, disparity_diff_720_20_rate = self.getDiff_Rate(disparity_avg720_list, disparity_avg20_list, duration=720) + disparity_diff_1440_20, disparity_diff_1440_20_rate = self.getDiff_Rate(disparity_avg1440_list, disparity_avg20_list, duration=1440) + + + """""" + 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 + + width_df = (upper_20 - lower_20) / middle_20 + width_min = np.min(width_df[0]) + width_max = np.max(width_df[0]) + bb_width_df = 100 * (width_df - width_min) / (width_max - width_min) + bb_pb_df = 100 * (close_df - lower_20) / (upper_20 - lower_20) + + 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)) + + np_high, np_low, np_close = np.array(high_scaled, dtype=np.float64), np.array(low_scaled, dtype=np.float64), np.array(close_scaled, dtype=np.float64) + slowk_5_df, slowd_5_df = talib.STOCH(np_high, np_low, np_close, fastk_period=5, slowk_period=3, slowk_matype=0, slowd_period=3, slowd_matype=0) + slowk_10_df, slowd_10_df = talib.STOCH(np_high, np_low, np_close, fastk_period=10, slowk_period=6, slowk_matype=0, slowd_period=6, slowd_matype=0) + slowk_20_df, slowd_20_df = talib.STOCH(np_high, np_low, np_close, fastk_period=20, slowk_period=12, slowk_matype=0, slowd_period=12, slowd_matype=0) + slowk_60_df, slowd_60_df = talib.STOCH(np_high, np_low, np_close, fastk_period=60, slowk_period=37, slowk_matype=0, slowd_period=37, slowd_matype=0) + slowk_120_df, slowd_120_df = talib.STOCH(np_high, np_low, np_close, fastk_period=120, slowk_period=74, slowk_matype=0, slowd_period=74, slowd_matype=0) + slowk_240_df, slowd_240_df = talib.STOCH(np_high, np_low, np_close, fastk_period=240, slowk_period=148, slowk_matype=0, slowd_period=148, slowd_matype=0) + slowk_480_df, slowd_480_df = talib.STOCH(np_high, np_low, np_close, fastk_period=480, slowk_period=296, slowk_matype=0, slowd_period=296, slowd_matype=0) + slowk_720_df, slowd_720_df = talib.STOCH(np_high, np_low, np_close, fastk_period=720, slowk_period=445, slowk_matype=0, slowd_period=445, slowd_matype=0) + slowk_1440_df, slowd_1440_df = talib.STOCH(np_high, np_low, np_close, fastk_period=1440, slowk_period=890, slowk_matype=0, slowd_period=890, slowd_matype=0) + willr = talib.WILLR(np_high, np_low, np_close, timeperiod=11) + 100 + rsi = talib.RSI(np_close, timeperiod=9) + rsi_720 = talib.RSI(np_close, timeperiod=720) + rsi_1440 = talib.RSI(np_close, timeperiod=1440) + macd, macds, macdo = talib.MACD(np_close, fastperiod=24, slowperiod=52, signalperiod=18) + macd_720, macds_720, macdo_720 = talib.MACD(np_close, fastperiod=332, slowperiod=720, signalperiod=250) + macd_1440, macds_1440, macdo_1440 = talib.MACD(np_close, fastperiod=665, slowperiod=1440, signalperiod=498) + + """ + """ + + df_list = [ + pd.DataFrame(ymd), + pd.DataFrame(open_scaled), pd.DataFrame(close_scaled), pd.DataFrame(high_scaled), pd.DataFrame(low_scaled), pd.DataFrame(volume_scaled), + pd.DataFrame(volume_rate), pd.DataFrame(head_rate), pd.DataFrame(body_rate), pd.DataFrame(tail_rate), + pd.DataFrame(open_low_rate), pd.DataFrame(open_high_rate), pd.DataFrame(open_open_rate), pd.DataFrame(open_close_rate), pd.DataFrame(close_low_rate), pd.DataFrame(close_high_rate), pd.DataFrame(close_open_rate), pd.DataFrame(close_close_rate), + + pd.DataFrame(list(support)), pd.DataFrame(list(resistance)), + pd.DataFrame(poly_5), pd.DataFrame(poly_10), pd.DataFrame(poly_20), pd.DataFrame(poly_60), pd.DataFrame(poly_120), pd.DataFrame(poly_240), pd.DataFrame(poly_480), pd.DataFrame(poly_720), pd.DataFrame(poly_1440), + + avg5_df, avg10_df, avg20_df, avg60_df, avg120_df, avg240_df, avg480_df, avg720_df, avg1440_df, + disparity_avg5_df, disparity_avg20_df, disparity_avg60_df, disparity_avg120_df, disparity_avg240_df, disparity_avg480_df, disparity_avg720_df, disparity_avg1440_df, disparity_avg2880_df, + pd.DataFrame(disparity_diff_20_5), pd.DataFrame(disparity_diff_20_5_rate), + pd.DataFrame(disparity_diff_60_20), pd.DataFrame(disparity_diff_60_20_rate), + pd.DataFrame(disparity_diff_120_20), pd.DataFrame(disparity_diff_120_20_rate), + pd.DataFrame(disparity_diff_240_20), pd.DataFrame(disparity_diff_240_20_rate), + pd.DataFrame(disparity_diff_480_20), pd.DataFrame(disparity_diff_480_20_rate), + pd.DataFrame(disparity_diff_720_20), pd.DataFrame(disparity_diff_720_20_rate), + pd.DataFrame(disparity_diff_1440_20), pd.DataFrame(disparity_diff_1440_20_rate), + + pd.DataFrame(new_high_7), pd.DataFrame(new_high_9), pd.DataFrame(new_high_26), pd.DataFrame(new_low_7), pd.DataFrame(new_low_9), pd.DataFrame(new_low_26), pd.DataFrame(high_th), + pd.DataFrame(upper_20), pd.DataFrame(lower_20), pd.DataFrame(middle_20), bb_width_df, bb_pb_df, pd.DataFrame(willr), + pd.DataFrame(slowk_5_df), pd.DataFrame(slowd_5_df), + pd.DataFrame(slowk_10_df), pd.DataFrame(slowd_10_df), + pd.DataFrame(slowk_20_df), pd.DataFrame(slowd_20_df), + pd.DataFrame(slowk_60_df), pd.DataFrame(slowd_60_df), + pd.DataFrame(slowk_120_df), pd.DataFrame(slowd_120_df), + pd.DataFrame(slowk_240_df), pd.DataFrame(slowd_240_df), + pd.DataFrame(slowk_480_df), pd.DataFrame(slowd_480_df), + pd.DataFrame(slowk_720_df), pd.DataFrame(slowd_720_df), + pd.DataFrame(slowk_1440_df), pd.DataFrame(slowd_1440_df), + pd.DataFrame(rsi), pd.DataFrame(rsi_720), pd.DataFrame(rsi_1440), + pd.DataFrame(macd), pd.DataFrame(macds), pd.DataFrame(macdo), + pd.DataFrame(macd_720), pd.DataFrame(macds_720), pd.DataFrame(macdo_720), + pd.DataFrame(macd_1440), pd.DataFrame(macds_1440), pd.DataFrame(macdo_1440), + + pd.DataFrame(open), pd.DataFrame(close), pd.DataFrame(high), pd.DataFrame(low), pd.DataFrame(volume) + ] + + data = pd.concat(df_list, axis=1) + column_names = [ + 'ymd', + 'open', 'close', 'high', 'low', 'volume', + 'volume_rate', 'head_rate', 'body_rate', 'tail_rate', + 'open_low_rate', 'open_high_rate', 'open_open_rate', 'open_close_rate', 'close_low_rate', 'close_high_rate', 'close_open_rate', 'close_close_rate', + + 'support', 'resistance', + 'poly_5', 'poly_10', 'poly_20', 'poly_60', 'poly_120', 'poly_240', 'poly_480', 'poly_720', 'poly_1440', + + 'avg5', 'avg10', 'avg20', 'avg60', 'avg120', 'avg240', 'avg480', 'avg720', 'avg1440', + 'disparity_avg5', 'disparity_avg20', 'disparity_avg60', 'disparity_avg120', 'disparity_avg240', 'disparity_avg480', 'disparity_avg720', 'disparity_avg1440', 'disparity_avg2880', + 'disparity_diff_20_5', 'disparity_diff_20_5_rate', + 'disparity_diff_60_20', 'disparity_diff_60_20_rate', + 'disparity_diff_120_20', 'disparity_diff_120_20_rate', + 'disparity_diff_240_20', 'disparity_diff_240_20_rate', + 'disparity_diff_480_20', 'disparity_diff_480_20_rate', + 'disparity_diff_720_20', 'disparity_diff_720_20_rate', + 'disparity_diff_1440_20', 'disparity_diff_1440_20_rate', + + 'new_high_7', 'new_high_9', 'new_high_26', 'new_low_7', 'new_low_9', 'new_low_26', 'high_th', + 'upper_20', 'lower_20', 'middle_20', 'bb_width', 'bb_pb', 'willr', + 'slowk_5', 'slowd_5', + 'slowk_10', 'slowd_10', + 'slowk_20', 'slowd_20', + 'slowk_60', 'slowd_60', + 'slowk_120', 'slowd_120', + 'slowk_240', 'slowd_240', + 'slowk_480', 'slowd_480', + 'slowk_720', 'slowd_720', + 'slowk_1440', 'slowd_1440', + 'rsi', 'rsi_720', 'rsi_1440', + 'macd', 'macds', 'macdo', + 'macd_720', 'macds_720', 'macdo_720', + 'macd_1440', 'macds_1440', 'macdo_1440', + + 'open_raw', 'close_raw', 'high_raw', 'low_raw', 'volume_raw' + ] + data.columns = column_names + data.index = pd.DatetimeIndex(ymd) + #data = data.dropna(axis=0) + return data, len(data) + + 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, None + + #result_tic = self.makeTickData(result_m1, mins=minute) + data_scale, ci = self.analyze_scale(result) + data, ci = self.analyze_raw(result) + + ticker['disparity_low_min'] = self.getDisparity_low_min(ticker, min='minutely') + + return data, data_scale, ci \ No newline at end of file diff --git a/LabelMaker.py b/LabelMaker.py deleted file mode 100644 index f5ad39b..0000000 --- a/LabelMaker.py +++ /dev/null @@ -1,130 +0,0 @@ -import os -import logging -logging.basicConfig(level=logging.INFO) -from stock.util.LabelChecker import LabelChecker - -class LabelMaker: - db_filename = None - labelChecker = None - - def __init__(self, RESOURCE_PATH): - self.labelChecker = LabelChecker(RESOURCE_PATH) - self.db_filename = os.path.join(RESOURCE_PATH, "hts.db") - return - - def clearLabel(self, stock_code, ymd): - self.labelChecker.clearLabel(self.db_filename, stock_code, ymd) - return - - def showLabels(self, stock_code, ymd): - self.labelChecker.showLabels(stock_code, ymd) - return - - def update(self, stock_code, ymd, hms, label): - self.labelChecker.makeLabel(self.db_filename, stock_code, ymd, hms, label) - return - - def write(self, stock_code, ymd, outFp): - logging.info(stock_code + " / " + ymd) - self.labelChecker.showLabels(stock_code, ymd, outFp) - return - - def check(self, stock_codes): - # 종목에 대해서 주어진 일자에 대해서 통계치 추출하기 - for stock_code in stock_codes: - ymds = self.labelChecker.getDate(stock_code) - for ymd in ymds: - logging.info(stock_code + " / " + ymd) - bsLine, data = self.labelChecker.makeCandidate(stock_code, ymd) - self.labelChecker.updateLabel(self.db_filename, stock_code, bsLine, data, ymd) - return - -if __name__ == "__main__": - PROJECT_HOME = os.path.join(os.path.dirname(__file__)) - RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources") - - labelMaker = LabelMaker(RESOURCE_PATH) - - - MODE = "WRITE" - if MODE == "UPDATE": - # 매일 입력하면서 정답 셋 만들기 - stock_code = "252670" - ymd = '20220531' - - labelMaker.clearLabel(stock_code, ymd) - - labelMaker.update(stock_code, ymd, "0901", 2) - labelMaker.update(stock_code, ymd, "0902", 2) - labelMaker.update(stock_code, ymd, "0903", 2) - labelMaker.update(stock_code, ymd, "1429", 2) - labelMaker.update(stock_code, ymd, "1430", 2) - labelMaker.update(stock_code, ymd, "1431", 2) - labelMaker.update(stock_code, ymd, "1432", 2) - labelMaker.update(stock_code, ymd, "1433", 2) - labelMaker.update(stock_code, ymd, "1434", 2) - labelMaker.update(stock_code, ymd, "1435", 2) - labelMaker.update(stock_code, ymd, "1436", 2) - labelMaker.update(stock_code, ymd, "1437", 2) - labelMaker.update(stock_code, ymd, "1438", 2) - labelMaker.update(stock_code, ymd, "1439", 2) - labelMaker.update(stock_code, ymd, "1440", 2) - labelMaker.update(stock_code, ymd, "1441", 2) - labelMaker.update(stock_code, ymd, "1442", 2) - labelMaker.update(stock_code, ymd, "1443", 2) - labelMaker.update(stock_code, ymd, "1444", 2) - labelMaker.update(stock_code, ymd, "1445", 2) - labelMaker.update(stock_code, ymd, "1446", 2) - labelMaker.update(stock_code, ymd, "1447", 2) - - labelMaker.update(stock_code, ymd, "0930", 1) - labelMaker.update(stock_code, ymd, "0931", 1) - labelMaker.update(stock_code, ymd, "0932", 1) - labelMaker.update(stock_code, ymd, "0933", 1) - labelMaker.update(stock_code, ymd, "0934", 1) - labelMaker.update(stock_code, ymd, "0935", 1) - labelMaker.update(stock_code, ymd, "1516", 1) - labelMaker.update(stock_code, ymd, "1517", 1) - labelMaker.update(stock_code, ymd, "1518", 1) - labelMaker.update(stock_code, ymd, "1519", 1) - - - labelMaker.showLabels(stock_code, ymd) - - else: - stock_codes = { - "252670": [ - '20220502', '20220503', '20220504', '20220506', '20220509', - '20220510', '20220511', '20220512', '20220513', '20220516', - '20220517', '20220518', '20220519', '20220520', '20220523', - '20220524', '20220525', '20220526', '20220527', '20220530', - '20220531', '20220602', '20220603', '20220607', '20220608', - '20220609', '20220610', '20220613', '20220614', '20220615', - '20220616', '20220617', '20220620', '20220621', '20220622', - '20220623', '20220624', '20220627', '20220628', '20220629', - '20220630', '20220624', '20220627', '20220628', '20220629', - '20220701', '20220704', '20220705', '20220706', '20220707', - '20220708', '20220711', '20220712', '20220713', '20220714', - '20220715', '20220718', '20220719', '20220720', '20220721', - '20220722', '20220725', '20220726', '20220727', '20220728', - '20220729', '20220801', '20220802', '20220803', '20220804', - '20220805', '20220808', '20220809', '20220810', '20220811', - '20220812', '20220816', '20220817', '20220818', '20220819'], - "122630": ['20220701', '20220704', '20220705', '20220706', '20220707', - '20220708', '20220711', '20220712', '20220713', '20220714', - '20220715', '20220718', '20220719', '20220720', '20220721', - '20220722', '20220725', '20220726', '20220727', '20220728', - '20220729', '20220801', '20220802', '20220803', '20220804', - '20220805', '20220808', '20220809', '20220810', '20220811', - '20220812', '20220816', '20220817'], - } - - if MODE == "WRITE": - for stock_code in stock_codes: - fileName = os.path.join(RESOURCE_PATH, "tmp", "check_"+stock_code+".txt") - outFp = open(fileName, "w") - for ymd in stock_codes[stock_code]: - labelMaker.write(stock_code, ymd, outFp) - outFp.close() - else: - labelMaker.check(stock_codes) \ No newline at end of file diff --git a/Simulation.py b/Simulation.py deleted file mode 100644 index c13a4bf..0000000 --- a/Simulation.py +++ /dev/null @@ -1,273 +0,0 @@ -from math import nan -import pandas as pd -import plotly.graph_objects as go -from plotly import subplots -import os -import sqlite3 - -from hts.HTS import HTS -from stock.util.Stock2Vector import Stock2Vector -from stock.util.LabelChecker import LabelChecker - -from hts.BuySellChecker import BuySellChecker - -class Simulation (HTS): - stock2Vector = None - buySellChecker = None - - def __init__(self, RESOURCE_PATH): - super().__init__(RESOURCE_PATH) - - self.RESOURCE_PATH = RESOURCE_PATH - - self.buySellChecker = BuySellChecker() - - try: - self.stock2Vector = Stock2Vector(RESOURCE_PATH) - self.labelChecker = LabelChecker(RESOURCE_PATH) - except: - pass - #self.connect() - return - - def draw(self, stock_code, given_day, data, bsLine): - if bsLine is None: - return - - # 어제 데이터는 지운다. - data = data.loc[pd.DatetimeIndex(data.index).day == int(given_day[6:])] - buy_line = bsLine['buy'][len(bsLine['buy'])-len(data):] - buy_weight_line = bsLine['buy_weight'][len(bsLine['buy'])-len(data):] - sell_line = bsLine['sell'][len(bsLine['buy'])-len(data):] - - # 그래프 설정을 위한 변수를 생성한다. - data = data.astype({'open': 'int', 'high': 'int', 'low': 'int', 'close': 'int', 'volume': 'int', - 'avg5': 'float', 'avg20': 'float', 'avg60': 'float', 'avg120': 'float', 'avg200': 'float', - 'disparity_avg5': 'float', 'disparity_avg20': 'float', 'disparity_avg60': 'float', 'disparity_avg120': 'float', 'disparity_avg200': 'float', - 'fast_k': 'float', 'slow_k': 'float', 'slow_d': 'float', - 'macd': 'float', 'macds': 'float', 'macdo': 'float', - 'rsi': 'float', 'rsis': 'float' - }) - - buy_size = [] - buy_colors = [] - for i in range(len(buy_line)): - if buy_line[i] < 0: - buy_colors.append("#ffffff") - buy_line[i] = nan - buy_size.append(0) - else: - buy_colors.append("#0C752E") - buy_size.append(10 + (5 * buy_weight_line[i])) - - sell_colors = [] - for i in range(len(sell_line)): - if sell_line[i] < 0: - sell_colors.append("#ffffff") - sell_line[i] = nan - else: - sell_colors.append("#00ced1") - - volume_colors = [] - for i in range(len(buy_line)): - if data['open'][i] > data['close'][i]: - volume_colors.append("#0000FF") - elif data['open'][i] < data['close'][i]: - volume_colors.append("#FF0000") - else: - volume_colors.append("#000000") - - # 그래프를 설정한다. - buy_check = go.Scatter(x=data['date'], y=buy_line, mode='markers', name="buy", marker=dict(size=buy_size, color=buy_colors, line_width=0)) - sell_check = go.Scatter(x=data['date'], y=sell_line, mode='markers', name="sell", marker=dict(size=14, color=sell_colors, line_width=0)) - - #volume_line = go.Scatter(x=data['date'], y=data["volume"], mode='lines', name='volume') - volume_line = go.Bar(x=data['date'], y=data["volume"], marker_color=volume_colors, name='volume') - - disparity_avg5 = go.Scatter(x=data['date'], y=data["disparity_avg5"], name="disparity_avg5", line_color='#F81191') - disparity_avg20 = go.Scatter(x=data['date'], y=data["disparity_avg20"], name="disparity_avg20", line_color='#097F19') - disparity_avg30 = go.Scatter(x=data['date'], y=data["disparity_avg30"], name="disparity_avg30", line_color='#097F19') - disparity_avg60 = go.Scatter(x=data['date'], y=data["disparity_avg60"], name="disparity_avg60", line_color='#671BEA') - disparity_avg120 = go.Scatter(x=data['date'], y=data["disparity_avg120"], name="disparity_avg120", line_color='#DFB809') - disparity_avg200 = go.Scatter(x=data['date'], y=data["disparity_avg200"], name="disparity_avg200", line_color='#000000') - - macd_line = go.Scatter(x=data['date'], y=data["macd"], line=dict(color='red', width=2), name='macd') - macd_s_line = go.Scatter(x=data['date'], y=data["macds"], line=dict(dash='dashdot', color='black', width=2), name='macds') - macd_o_line = go.Bar(x=data['date'], y=data["macdo"], marker_color='purple', name='macdo') - - # fast_k_line = go.Scatter(x=hts['date'], y=hts["fast_k"], mode='lines', name='fast_k') - slow_k_line = go.Scatter(x=data['date'], y=data["slow_k"], line=dict(color='red', width=2), name='slow_k') - slow_d_line = go.Scatter(x=data['date'], y=data["slow_d"], line=dict(dash='dashdot', color='black', width=2), name='slow_d') - - rsi_line = go.Scatter(x=data['date'], y=data["rsi"], line=dict(color='red', width=2), name='rsi') - rsis_line = go.Scatter(x=data['date'], y=data["rsis"], line=dict(dash='dashdot', color='black', width=2), name='rsis') - - upper = go.Scatter(x=data['date'], y=data["upper"], name="upper", line_color='#000000') - lower = go.Scatter(x=data['date'], y=data["lower"], name="lower", line_color='#000000') - - avg5 = go.Scatter(x=data['date'], y=data["avg5"], name="avg5", line_color='#F81191') - avg20 = go.Scatter(x=data['date'], y=data["avg20"], name="avg20", line_color='#097F19') - avg30 = go.Scatter(x=data['date'], y=data["avg30"], name="avg30", line_color='#097F19') - avg60 = go.Scatter(x=data['date'], y=data["avg60"], name="avg60", line_color='#671BEA') - avg120 = go.Scatter(x=data['date'], y=data["avg120"], name="avg120", line_color='#DFB809') - avg200 = go.Scatter(x=data['date'], y=data["avg200"], name="avg200", line_color='#000000') - - changeLine = go.Scatter(x=data['date'], y=data["changeLine"], name='changeLine', line_color='#14A200') #CF6E0D - baseLine = go.Scatter(x=data['date'], y=data["baseLine"], name='baseLine', line_color='orange') - laggingSpan = go.Scatter(x=data['date'], y=data["laggingSpan"], name='laggingSpan', line_color='#B50ABB') - leadingSpan1 = go.Scatter(x=data['date'], y=data["leadingSpan1"], name='leadingSpan1', line_color='black') - leadingSpan2 = go.Scatter(x=data['date'], y=data["leadingSpan2"], name='leadingSpan2', line_color='black') - - text_list = [] - for i in range(len(data['macd'])): - text = "{}

open: {}
close: {}
high: {}
low: {}
volume: {}

avg5: {:.2f}
avg20: {:.2f}
avg60: {:.2f}
avg200: {:.2f}

d_avg5: {:.6f}
d_avg20: {:.6f}
d_avg60: {:.6f}
d_avg200: {:.6f}
d_avg5_60: {:.6f}
d_avg5_200: {:.6f}
d_avg200-5: {:.6f}

macd: {:.2f}
slow_k: {:.2f}
rsi: {:.2f}".format( - data['date'][i], - data['open'][i],data['close'][i],data['high'][i],data['low'][i],data['volume'][i], - data['avg5'][i],data['avg20'][i],data['avg60'][i],data['avg200'][i], - data['disparity_avg5'][i], data['disparity_avg20'][i], data['disparity_avg60'][i], data['disparity_avg200'][i], - max(data['disparity_avg5'][i], data['disparity_avg20'][i], data['disparity_avg60'][i]) - min(data['disparity_avg5'][i], data['disparity_avg20'][i], data['disparity_avg60'][i]), - max(data['disparity_avg5'][i], data['disparity_avg20'][i], data['disparity_avg60'][i], data['disparity_avg200'][i]) - min(data['disparity_avg5'][i], data['disparity_avg20'][i], data['disparity_avg60'][i], data['disparity_avg200'][i]), - abs(data['disparity_avg200'][i] - data['disparity_avg5'][i]), - data['macd'][i],data['slow_k'][i],data['rsi'][i] - ) - text_list.append(text) - - candle_stick = go.Candlestick(x=data['date'], - open=data['open'], - high=data['high'], - low=data['low'], - close=data['close'], - increasing_line_color='red', - decreasing_line_color='blue', - showlegend=False, - text=text_list, - hoverinfo="text" - ) - - # candle_data = [avg5, avg20, avg30, avg60, avg120, avg200, buy_check, sell_check, laggingSpan, changeLine, baseLine, upper, lower, candle_stick] - # candle_data = [avg5, avg20, avg30, avg60, avg200, buy_check, sell_check, upper, lower, candle_stick] - # candle_data = [buy_check, sell_check, changeLine, baseLine, changeLine, laggingSpan, candle_stick] - candle_data = [avg5, avg200, buy_check, sell_check, candle_stick] - - volume_data = [volume_line] - disparity_data = [disparity_avg5, disparity_avg20, disparity_avg30, disparity_avg60, disparity_avg120, disparity_avg200] - macd_data = [macd_line, macd_s_line, macd_o_line] - stochastic_data = [slow_k_line, slow_d_line] - rsi_data = [rsi_line, rsis_line] - - # 그래프를 그린다. - """ - fig = go.Figure(data=candle_data) - fig.update_layout(title=stock_code + "_" + given_day) - fig.show() - """ - - fig = subplots.make_subplots( - rows=6, cols=1, - subplot_titles=("거래량", "이격도", "스토캐스틱", "RSI", "MACD", '캔들'), - #specs=[[{}], [{}], [{}], [{}], [{}], [{}]], - shared_xaxes=True, horizontal_spacing=0.03, vertical_spacing=0.01, - row_heights=[200, 200, 200, 200, 200, 700] - ) - for trace in volume_data: - fig.append_trace(trace, 1, 1) - for trace in disparity_data: - fig.append_trace(trace, 2, 1) - for trace in stochastic_data: - fig.append_trace(trace, 3, 1) - for trace in rsi_data: - fig.append_trace(trace, 4, 1) - for trace in macd_data: - fig.append_trace(trace, 5, 1) - for trace in candle_data: - fig.append_trace(trace, 6, 1) - - #fig.update_xaxes(nticks=5) - #fig.update_layout(height=1800, title=stock_code + "_" + given_day, xaxis_rangeslider_visible=False) - - df = pd.DataFrame(bsLine) - df = df.fillna(-1) - buy_count = len(df.loc[df["buy"] > 0]) - sell_count = len(df.loc[df["sell"] > 0]) - - fig.update_layout(height=1700, title=stock_code + "_" + given_day + "_" + str(buy_count)+","+str(sell_count)) - #fig.update_layout(title=stock_code + "_" + given_day + "_" + str(buy_count) + "," + str(sell_count)) - fig.show() - - return - - - def makeTickData(self, data, mins=30): - result = {"check": set(), - "time": [], - "open": [], - "close": [], - "high": [], - "low": [], - "vol": [], - "label": []} - - for i in range(mins, len(data['time'])+1): - result["check"].add(data['time'][i-1]) - result["time"].append(data['time'][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["vol"].append(sum(data['vol'][i - mins: i])) - - return result - - def simulate(self, stock, analyzed_day=1000): - stock_code = stock['code'] - for ymd in stock['ymd']: - LAST_DATA = self.stock2Vector.getLastData(stock_code, ymd) - # 1분봉 - result = self.stock2Vector.getRealTime(stock_code, ymd, LAST_DATA) - # 5분봉 - #result = self.makeTickData(result, mins=5) - # 30분봉 - #result = self.makeTickData(result, mins=30) - - data = self.buySellChecker.analyze(result) - data.drop(data.index[:len(data) - analyzed_day], inplace=True) - - # 이동평균, RSI, MACD, 일목균형, 볼린저밴드 상/하단을 계산한다. - #data_5 = self.buySellChecker.analyze(result_5) - # 분석일 데이터만 활용한다 (이전 데이터는 제거) - #data_5.drop(data_5.index[:len(data_5) - analyzed_day], inplace=True) - - #data_30 = self.buySellChecker.analyze(result_30) - # 분석일 데이터만 활용한다 (이전 데이터는 제거) - #data_30.drop(data_30.index[:len(data_30) - analyzed_day], inplace=True) - - # 사야 할 시점과 팔아야 할 시점을 체크한다. - #bsLine = self.buySellChecker.checkTransaction(stock_code, data, data_5, data_30, isRealTime=False) - - # 어제 데이터는 지운다. - #data = data.loc[pd.DatetimeIndex(data.index).day == int(given_day[6:])] - bsLine = self.buySellChecker.checkTransaction(data, isRealTime=False) - - # 그래프를 그린다. - self.draw(stock_code, ymd, data, bsLine) - return - -if __name__ == "__main__": - - PROJECT_HOME = os.getcwd() - RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources") - - #day_list = ['20231016', '20231017', '20231018', '20231019', '20231020', '20231023', '20231024', '20231025', '20231026', '20231027', '20231030', '20231031', '20231101', '20231102'] - day_list = ['20231113'] - stocks = [ - {'code': '252670', 'name': 'KODEX 200선물인버스2X', 'ymd': day_list}, - {'code': '122630', 'name': 'KODEX 레버리지', 'ymd': day_list}, - {'code': '233740', 'name': 'KODEX 코스닥150레버리지', 'ymd': day_list}, - {'code': '251340', 'name': 'KODEX 코스닥150선물인버스', 'ymd': day_list} - ] - - for stock in stocks: - simulation = Simulation(RESOURCE_PATH) - simulation.simulate(stock) - print ("done...") diff --git a/StockCrawler.py b/StockCrawler.py index 6858bb8..fe57750 100644 --- a/StockCrawler.py +++ b/StockCrawler.py @@ -1,15 +1,10 @@ import os -import re import sys -import shutil import time -import sqlite3 from datetime import datetime -from dateutil.relativedelta import relativedelta from stock.crawler.FnGuideCrawler import FnGuideCrawler from stock.crawler.MetaCrawler import MetaCrawler from stock.crawler.StockCrawler import StockCrawler -from stock.analysis.AnalyzerSqlite import AnalyzerSqlite class StockCrawlerDaily: @@ -113,27 +108,6 @@ class StockCrawlerDaily: print("\n[US 종목 수집]") stockCrawler.crawl_special_stocks(stockFileName) - analyzerSqlite = AnalyzerSqlite(RESOURCE_PATH) - - print("\n[종목 결정]") - # HTML 출력 - outPath = os.path.join(self.PROJECT_HOME, "resources", "analysis") - if not os.path.isdir(outPath): - os.mkdir(outPath) - day = datetime.today().strftime("%Y%m%d") - before_7_day = datetime.today() + relativedelta(days=-7) - dayList = os.listdir(outPath) - for dayDir in dayList: - if dayDir[0] != '.' and dayDir < before_7_day.strftime("%Y%m%d"): - if os.path.exists(os.path.join(outPath, dayDir)) and os.path.isdir(os.path.join(outPath, dayDir)): - shutil.rmtree(os.path.join(outPath, dayDir)) - outPath = os.path.join(outPath, day) - if os.path.isdir(outPath): - shutil.rmtree(outPath) - os.mkdir(outPath) - - analyzerSqlite.findCandidates(outPath) - return diff --git a/StockPredictorAPI.py b/StockPredictorAPI.py deleted file mode 100644 index 8e3dfea..0000000 --- a/StockPredictorAPI.py +++ /dev/null @@ -1,7 +0,0 @@ -from fastapi import FastAPI - -app = FastAPI() - -@app.get("/") -async def root(): - return {"message": "Hello World"} \ No newline at end of file diff --git a/StockTrainer.py b/StockTrainer.py deleted file mode 100644 index 1727f6b..0000000 --- a/StockTrainer.py +++ /dev/null @@ -1,65 +0,0 @@ -import os -import keras -import numpy as np -import tensorflow as tf -from stock.util.Stock2Vector import Stock2Vector -from classification_models.keras import Classifiers - -class StockTrainer: - - RESOURCE_PATH = None - stock2Vector = None - - def __init__(self, RESOURCE_PATH): - self.RESOURCE_PATH = RESOURCE_PATH - self.stock2Vector = Stock2Vector(RESOURCE_PATH) - return - - - def train(self, stock_code): - #X, Y = self.stock2Vector.getDataset3D(stock_code) - X, Y = self.stock2Vector.getDataset2D(stock_code) - - # build model - n_classes = 3 - Inceptionresnetv2, preprocess_input = Classifiers.get('inceptionresnetv2') - X = preprocess_input(X) - - # train - checkpoint_filename = os.path.join(self.RESOURCE_PATH, "model", "stock.ckpt") - base_model = Inceptionresnetv2(input_shape=(299, 299, 3), include_top=False) - x = tf.keras.layers.GlobalAveragePooling2D()(base_model.output) - output = tf.keras.layers.Dense(n_classes, activation='softmax')(x) - model = keras.models.Model(inputs=[base_model.input], outputs=[output]) - - model.compile(optimizer='SGD', loss='categorical_crossentropy', metrics=['accuracy']) - chekpoint = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_filename, save_weights_only=True, verbose=1) - earlystop = tf.keras.callbacks.EarlyStopping(monitor='loss', patience=5, mode="auto") - - if os.path.isfile(checkpoint_filename): - model.load_weights(checkpoint_filename) - - model.fit(x=X, - y=Y, - batch_size=10000, - epochs=10000, - callbacks=[chekpoint, earlystop]) - - return - - -if __name__ == "__main__": - PROJECT_HOME = os.getcwd() - RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources") - - stock_codes = { - # 252670 - # 122630 - "252670": ['20220729'], - } - - for stock_code in stock_codes: - stockTrainer = StockTrainer(RESOURCE_PATH) - stockTrainer.train(stock_code) - - print ("done...") \ No newline at end of file diff --git a/VitTrainer.py b/VitTrainer.py deleted file mode 100755 index 505cd06..0000000 --- a/VitTrainer.py +++ /dev/null @@ -1,240 +0,0 @@ -# tensor - numpy - PILImage 변환 (https://qlsenddl-lab.tistory.com/37) - -import os -os.environ['KMP_DUPLICATE_LIB_OK']='True' -import random -import numpy as np -import torch -from datasets import Dataset, load_metric, ClassLabel -from datasets import load_metric -from transformers import ViTConfig, TrainingArguments, Trainer, ViTForImageClassification -from torch.utils.data import DataLoader -import torchvision.transforms as transforms -from transformers import ViTFeatureExtractor -from torchvision.transforms import (CenterCrop, Compose, Normalize, RandomHorizontalFlip, RandomResizedCrop, Resize, ToTensor) - -from stock.util.Stock2Vector import Stock2Vector - -class VitTrainer: - - RESOURCE_PATH = None - stock2Vector = None - - num_labels = None - id2label = None - label2id = None - - args = None - - _train_transforms = None - _val_transforms = None - - def __init__(self, RESOURCE_PATH): - self.set_seed(42) - - self.RESOURCE_PATH = RESOURCE_PATH - self.stock2Vector = Stock2Vector(RESOURCE_PATH) - - self.num_labels = 3 - self.id2label = {0: 'none', 1: 'sell', 2: 'buy'} - self.label2id = {'none': 0, 'sell': 1, 'buy': 2} - - self.args = TrainingArguments( - os.path.join(self.RESOURCE_PATH, 'model', f"stock_vit_predictor"), - save_strategy="epoch", - evaluation_strategy="epoch", - learning_rate=2e-5, - per_device_train_batch_size=128, - per_device_eval_batch_size=128, - weight_decay=0.01, - load_best_model_at_end=True, - metric_for_best_model="accuracy", - logging_dir=os.path.join(self.RESOURCE_PATH, 'model', 'logs'), - remove_unused_columns=False, - num_train_epochs=24, - ) - - return - - def set_seed(self, seed=42, n_gpu=0): - random.seed(seed) - np.random.seed(seed) - torch.manual_seed(seed) - if n_gpu > 0: - torch.cuda.manual_seed_all(seed) - - def train_transforms(self, examples): - examples['pixel_values'] = [self._train_transforms(image.convert("RGB")) for image in examples['img']] - return examples - - def val_transforms(self, examples): - examples['pixel_values'] = [self._val_transforms(image.convert("RGB")) for image in examples['img']] - return examples - - def collate_fn(self, examples): - pixel_values = torch.stack([example["pixel_values"] for example in examples]) - labels = torch.tensor([example["label"] for example in examples]) - return {"pixel_values": pixel_values, "labels": labels} - - def compute_metrics(self, eval_pred): - predictions, labels = eval_pred - predictions = np.argmax(predictions, axis=1) - metric = load_metric("accuracy") - return metric.compute(predictions=predictions, references=labels) - - def getFeature(self, model_path=None): - if model_path == None: - self.feature_extractor = ViTFeatureExtractor.from_pretrained("google/vit-base-patch16-224-in21k") - #self.feature_extractor = ViTFeatureExtractor() - else: - #self.feature_extractor = ViTFeatureExtractor.from_pretrained("google/vit-base-patch16-224-in21k") - self.feature_extractor = ViTFeatureExtractor.from_pretrained(model_path) - - normalize = Normalize(mean=self.feature_extractor.image_mean, std=self.feature_extractor.image_std) - self._train_transforms = Compose( - [ - RandomResizedCrop(self.feature_extractor.size), - RandomHorizontalFlip(), - ToTensor(), - normalize, - ] - ) - - self._val_transforms = Compose( - [ - Resize(self.feature_extractor.size), - CenterCrop(self.feature_extractor.size), - ToTensor(), - normalize, - ] - ) - return - - def train(self, train_ds, val_ds, model_path): - self.getFeature() - - # Set the transforms - train_ds.set_transform(self.train_transforms) - val_ds.set_transform(self.val_transforms) - - train_dataloader = DataLoader(train_ds, collate_fn=self.collate_fn, batch_size=32) - - batch = next(iter(train_dataloader)) - for k,v in batch.items(): - if isinstance(v, torch.Tensor): - print(k, v.shape) - - """ - model = ViTForImageClassification.from_pretrained('google/vit-base-patch16-224-in21k', - num_labels=self.num_labels, - id2label=self.id2label, - label2id=self.label2id) - """ - configuration = ViTConfig(num_labels=self.num_labels, - id2label=self.id2label, - label2id=self.label2id) - model = ViTForImageClassification(configuration) - - trainer = Trainer( - model, - self.args, - train_dataset=train_ds, - eval_dataset=val_ds, - data_collator=self.collate_fn, - compute_metrics=self.compute_metrics, - tokenizer=self.feature_extractor - ) - - trainer.train() - - # save trained model - model_to_save = (model.module if hasattr(model, "module") else model) # Take care of distributed/parallel training - model_to_save.save_pretrained(model_path) - self.feature_extractor.save_pretrained(model_path) - torch.save(self.args, os.path.join(RESOURCE_PATH, "model", "training_args.bin")) - - return - - def finetunning(self, train_ds, val_ds, model_path): - self.getFeature(model_path) - - # Set the transforms - train_ds.set_transform(self.train_transforms) - val_ds.set_transform(self.val_transforms) - - train_dataloader = DataLoader(train_ds, collate_fn=self.collate_fn, batch_size=32) - - batch = next(iter(train_dataloader)) - for k,v in batch.items(): - if isinstance(v, torch.Tensor): - print(k, v.shape) - - model = ViTForImageClassification.from_pretrained(model_path, - num_labels=self.num_labels, - id2label=self.id2label, - label2id=self.label2id) - trainer = Trainer( - model, - self.args, - train_dataset=train_ds, - eval_dataset=val_ds, - data_collator=self.collate_fn, - compute_metrics=self.compute_metrics, - tokenizer=self.feature_extractor - ) - - trainer.train() - - # save trained model - model_to_save = (model.module if hasattr(model, "module") else model) # Take care of distributed/parallel training - model_to_save.save_pretrained(model_path) - self.feature_extractor.save_pretrained(model_path) - torch.save(self.args, os.path.join(RESOURCE_PATH, "model", "training_args.bin")) - - return - - def getData(self, stock_code, sDate, eDate): - # Instance Normalization를 NumPy 및 PyTorch로 구현하는 방법! (https://ndb796.tistory.com/653) - data = self.stock2Vector.getTrainData(stock_code, sDate, eDate) - #X, Y = self.stock2Vector.getDataset2D(data) - X, Y = self.stock2Vector.getVectorData(data) - print("Data count: ", len(X)) - - trans = transforms.ToPILImage() - #X = [trans(torch.tensor([x])) for x in X] - X = [trans(torch.tensor(x)) for x in X] - - split_point1 = int(len(X) * 0.9) - train_X = X[:split_point1] - train_Y = Y[:split_point1] - valid_X = X[split_point1:] - valid_Y = Y[split_point1:] - - # load cifar10 (only small portion for demonstration purposes) - train_data = {'img': train_X, 'label': train_Y} - val_dsta = {'img': valid_X, 'label': valid_Y} - - train_ds = Dataset.from_dict(train_data) - val_ds = Dataset.from_dict(val_dsta) - - features = train_ds.features.copy() - features["label"] = ClassLabel(num_classes=self.num_labels, names=["none", "sell", "buy"]) - def adjust_labels(batch): - batch["label"] = [lbl for lbl in batch["label"]] - return batch - train_ds = train_ds.map(adjust_labels, batched=True, features=features) - val_ds = train_ds.map(adjust_labels, batched=True, features=features) - - return train_ds, val_ds - -if __name__ == "__main__": - - PROJECT_HOME = os.getcwd() - RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources") - model_path = os.path.join(RESOURCE_PATH, "model") - - stock_code = "252670" - vitTrainer = VitTrainer(RESOURCE_PATH) - - train_ds, val_ds = vitTrainer.getData(stock_code, sDate="20220501", eDate="20220819") - vitTrainer.train(train_ds, val_ds, model_path) diff --git a/stock/analysis/AnalyzerSqlite.py b/stock/analysis/AnalyzerSqlite.py deleted file mode 100644 index b93b5d1..0000000 --- a/stock/analysis/AnalyzerSqlite.py +++ /dev/null @@ -1,594 +0,0 @@ -import os -import time -import shutil -import matplotlib.pyplot as plt -import datetime -import sqlite3 -import math -from math import nan -from datetime import datetime, timedelta -from dateutil.relativedelta import relativedelta -from matplotlib import rc -import pandas as pd -import numpy as np -from stock.analysis.JSDPattern_simulation import JSDPattern_simulation -from hts.BuySell_Daily import BuySell_Daily - -rc('font', family='AppleGothic') -plt.rcParams['axes.unicode_minus'] = False - -import plotly.graph_objs as go -from plotly import subplots -import plotly.io as po - -from stock.analysis.Common import Common -from stock.util.TelegramBot import TelegramBot - -class AnalyzerSqlite: - jSDPattern = None - buySell_Daily = None - topCompany = None - fnguide = None - - bot = None - - common = None - stockFileName = None - analyzedFileName = None - - moving_avg = None - - def __init__(self, RESOURCE_PATH): - self.common = Common() - - self.stockFileName = os.path.join(RESOURCE_PATH, 'stock.db') - self.jSDPattern = JSDPattern_simulation(self.stockFileName) - self.buySell_Daily = BuySell_Daily() - self.stockFileName = self.stockFileName - self.topCompany = self.getTopCompany(self.stockFileName, 2000) - self.fnguide = self.readFnguide(self.stockFileName) - - self.bot = TelegramBot() - - return - - def getTopCompany(self, fnguideFileName, top): - conn = sqlite3.connect(fnguideFileName) - cursor = conn.cursor() - - sql = "select DISTINCT CODE, NAME from fnguide order by total_ownership_interest desc limit " + str(top) - cursor.execute(sql) - result = cursor.fetchall() - - top_company = {} - for idx, item in enumerate(result): - top_company[item[0]] = (idx+1, item[1]) - - cursor.close() - conn.close() - return top_company - - def readFnguide(self, fnguideFileName): - conn = sqlite3.connect(fnguideFileName) - cursor = conn.cursor() - - today = datetime.today() - year1 = str(today.year - 1) + ".12.01" - year2 = str(today.year - 2) + ".12.01" - year3 = str(today.year - 3) + ".12.01" - - sql = "SELECT CODE, NAME, ymd, business_profits, business_profits_ratio, debt_ratio, ROA, ROE, EPS, BPS, DPS, PER, PBR FROM fnguide " - sql += " WHERE (ymd=? or ymd=? or ymd=?) and type=''" - sql += " order by code, ymd desc" - cursor.execute(sql, (year1,year2,year3)) - result = cursor.fetchall() - - fnguide = {} - for item in result: - if item[0] not in fnguide: - fnguide[item[0]] = [] - - fnguide[item[0]].append( - {'NAME': item[1], - 'ymd': item[2], - 'business_profits': item[3], - 'business_profits_ratio': item[4], - 'debt_ratio': item[5], - 'ROA': item[6], - 'ROE': item[7], - 'EPS': item[8], - 'BPS': item[9], - 'DPS': item[10], - 'PER': item[11], - 'PBR': item[12]}) - - cursor.close() - conn.close() - return fnguide - - - def cz(self, value): - if value is None or math.isnan(value): - return 0 - - return value - - - def clear_BSLINE(self, BUY_LIST, sell_type=None): - if sell_type is None or sell_type == '': - BUY_LIST['avg_buy_price'] = 0 - BUY_LIST['buy_count'] = 0 - BUY_LIST['buy_list'].clear() - else: - BUY_LIST['avg_buy_price'] = 0 - BUY_LIST['buy_count'] = 0 - - tmp_sell_type = sell_type.split(',') - for i, buy_list in reversed(list(enumerate(BUY_LIST['buy_list']))): - for t_sell_type in tmp_sell_type: - if buy_list['buy_type'].strip() == t_sell_type.strip(): - del BUY_LIST['buy_list'][i] - break - return - - def draw(self, stock_code, data, bsLine=None): - - # 어제 데이터는 지운다. - #data = data.loc[pd.DatetimeIndex(data.index).day == int(given_day[6:])] - buy_price_line, buy_count_line, buy_type, buy_count_line, sell_price_line, sell_count_line, sell_type = [], [], [], [], [], [], [] - buy_sell_size, buy_colors, sell_colors, buy_colors = [], [], [], [] - - if bsLine is not None: - buy_price_line = bsLine['buy_price'] - buy_count_line = bsLine['buy_count'] - sell_price_line = bsLine['sell_price'] - sell_count_line = bsLine['sell_count'] - buy_type = bsLine['buy_type'] - sell_type = bsLine['sell_type'] - - for i in range(len(data)): - if buy_price_line[i] < 1: - buy_colors.append("#ffffff") - buy_price_line[i] = nan - buy_sell_size.append(0) - else: - buy_colors.append("#0C752E") - buy_sell_size.append(14) - for i in range(len(data)): - if sell_price_line[i] < 1: - sell_colors.append("#ffffff") - sell_price_line[i] = nan - else: - sell_colors.append("#00ced1") - - volume_colors = [] - for i in range(len(data)): - if data['open'][i] > data['close'][i]: - volume_colors.append("#FF0000") - elif data['open'][i] < data['close'][i]: - volume_colors.append("#FF0000") - else: - volume_colors.append("#000000") - - # 그래프를 설정한다. - if bsLine is not None: - buy_text_list, sell_text_list = [], [] - for i in range(len(data['ymd'])): - buy_text_list.append( - "{}, {}, {} ({:,.2f})

" - "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_avg60_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_avg60_diff'][i]), self.cz(data['laggingSpan_avg60_diff_rate'][i]), - self.cz(data['leadingSpan1_leadingSpan2_diff'][i]), self.cz(data['leadingSpan1_leadingSpan2_diff_rate'][i]) - )) - sell_text_list.append( - "{}, {}, {} ({:,.2f})

" - "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_avg60_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_avg60_diff'][i]), self.cz(data['laggingSpan_avg60_diff_rate'][i]), - self.cz(data['leadingSpan1_leadingSpan2_diff'][i]), self.cz(data['leadingSpan1_leadingSpan2_diff_rate'][i]) - )) - buy_check = go.Scatter(x=data['ymd'], y=buy_price_line, mode='markers', name="buy_price", marker=dict(size=buy_sell_size, color=buy_colors, line_width=0), text=buy_text_list, hoverinfo="text") - sell_check = go.Scatter(x=data['ymd'], y=sell_price_line, mode='markers', name="sell_price", marker=dict(size=14, color=sell_colors, line_width=0), text=sell_text_list, hoverinfo="text") - - volume_line = go.Bar(x=data['ymd'], y=data["volume"], marker_color=volume_colors, name='volume') - - avg5 = go.Scatter(x=data['ymd'], y=data["avg5"], name="avg5", line_color='#079118') - avg10 = go.Scatter(x=data['ymd'], y=data["avg10"], name="avg10", line_color='grey') - avg20 = go.Scatter(x=data['ymd'], y=data["avg20"], name="avg20", line_color='#d755e8') - avg60 = go.Scatter(x=data['ymd'], y=data["avg60"], name="avg60", line_color='#099B92') - avg90 = go.Scatter(x=data['ymd'], y=data["avg90"], name="avg90", line_color='#2a9c0c') - avg120 = go.Scatter(x=data['ymd'], y=data["avg120"], name="avg120", line_color='#079118') - avg240 = go.Scatter(x=data['ymd'], y=data["avg240"], name="avg240", line_color='#e68456') - avg360 = go.Scatter(x=data['ymd'], y=data["avg360"], name="avg360", line_color='#e6b55c') - avg480 = go.Scatter(x=data['ymd'], y=data["avg480"], name="avg480", line_color='#2a9c0c') - avg720 = go.Scatter(x=data['ymd'], y=data["avg720"], name="avg720", line_color='#e75d53') - avg1440 = go.Scatter(x=data['ymd'], y=data["avg1440"], name="avg1440", line_color='#2a9c0c') - avg2880 = go.Scatter(x=data['ymd'], y=data["avg2880"], name="avg2880", line_color='#46406c') - - laggingSpan_0_8_limit = [0.8 for i in data['ymd']] - laggingSpan_0_2_limit = [0.2 for i in data['ymd']] - laggingSpan_0_limit = [0 for i in data['ymd']] - laggingSpan__0_2_limit = [-0.2 for i in data['ymd']] - laggingSpan__0_8_limit = [-0.8 for i in data['ymd']] - laggingSpan_0_8_limit_line = go.Scatter(x=data['ymd'], y=laggingSpan_0_8_limit, line=dict(color='grey', width=1), name='laggingSpan_0_8_limit') - laggingSpan_0_2_limit_line = go.Scatter(x=data['ymd'], y=laggingSpan_0_2_limit, line=dict(color='grey', width=1), name='laggingSpan_0_2_limit') - laggingSpan_0_limit_line = go.Scatter(x=data['ymd'], y=laggingSpan_0_limit, line=dict(color='grey', width=1), name='laggingSpan_0_limit') - laggingSpan__0_2_limit_line = go.Scatter(x=data['ymd'], y=laggingSpan__0_2_limit, line=dict(color='grey', width=1), name='laggingSpan__0_2_limit') - laggingSpan__0_8_limit_line = go.Scatter(x=data['ymd'], y=laggingSpan__0_8_limit, line=dict(color='grey', width=1), name='laggingSpan__0_8_limit') - - laggingSpan_close_diff = go.Scatter(x=data['ymd'], y=data["laggingSpan_close_diff"], name="laggingSpan_close_diff", line_color='#079118') - laggingSpan_avg60_diff = go.Scatter(x=data['ymd'], y=data["laggingSpan_avg60_diff"], name="laggingSpan_avg60_diff", line_color='#d755e8') - leadingSpan1_leadingSpan2_diff = go.Scatter(x=data['ymd'], y=data["leadingSpan1_leadingSpan2_diff"], name="leadingSpan1_leadingSpan2_diff", line_color='#d755e8') - - laggingSpan_close_diff_rate = go.Scatter(x=data['ymd'], y=data["laggingSpan_close_diff_rate"], name="laggingSpan_close_diff_rate", line_color='#d755e8') - laggingSpan_avg60_diff_rate = go.Scatter(x=data['ymd'], y=data["laggingSpan_avg60_diff_rate"], name="laggingSpan_avg60_diff_rate", line_color='#d755e8') - leadingSpan1_leadingSpan2_diff_rate = go.Scatter(x=data['ymd'], y=data["leadingSpan1_leadingSpan2_diff_rate"], name="leadingSpan1_leadingSpan2_diff_rate", line_color='#d755e8') - - changeLine = go.Scatter(x=data['ymd'], y=data["changeLine"], name="changeLine", line_color='#0196ff') - baseLine = go.Scatter(x=data['ymd'], y=data["baseLine"], name="baseLine", line_color='#991515') - laggingSpan = go.Scatter(x=data['ymd'], y=data["laggingSpan"], name="laggingSpan", line_color='#12A524') - leadingSpan1 = go.Scatter(x=data['ymd'], y=data["leadingSpan1"], name="leadingSpan1", line_color='#008001') - leadingSpan2 = go.Scatter(x=data['ymd'], y=data["leadingSpan2"], name="leadingSpan2", line_color='#830fd4') - - upper_10_Line = go.Scatter(x=data['ymd'], y=data["upper_10"], name="upper_10", line_color='#0196ff') - lower_10_Line = go.Scatter(x=data['ymd'], y=data["lower_10"], name="lower_10", line_color='#991515') - middle_10_line = go.Scatter(x=data['ymd'], y=data["middle_10"], name="middle_10", line_color='#12A524') - upper_20_Line = go.Scatter(x=data['ymd'], y=data["upper_20"], name="upper_20", line_color='#0196ff') - lower_20_Line = go.Scatter(x=data['ymd'], y=data["lower_20"], name="lower_20", line_color='#991515') - middle_20_line = go.Scatter(x=data['ymd'], y=data["middle_20"], name="middle_20", line_color='#12A524') - - loc_240_k = go.Scatter(x=data['ymd'], y=data["loc_240_k"], name="loc_240_k", line_color='#0196ff') - loc_240_d = go.Scatter(x=data['ymd'], y=data["loc_240_d"], name="loc_240_d", line_color='#991515') - loc_240_s = go.Scatter(x=data['ymd'], y=data["loc_240_s"], name="loc_240_s", line_color='#12A524') - - new_high_9 = go.Scatter(x=data['ymd'], y=data["new_high_9"], name="new_high_9", line_color='#0196ff') - new_high_26 = go.Scatter(x=data['ymd'], y=data["new_high_26"], name="new_high_26", line_color='#991515') - new_low_9 = go.Scatter(x=data['ymd'], y=data["new_low_9"], name="new_low_9", line_color='#0196ff') - new_low_26 = go.Scatter(x=data['ymd'], y=data["new_low_26"], name="new_low_26", line_color='#991515') - - - slowk_up_limit = [80 for i in data['ymd']] - slowk_middle_limit = [50 for i in data['ymd']] - slowk_down_limit = [20 for i in data['ymd']] - slowk_up_limit = go.Scatter(x=data['ymd'], y=slowk_up_limit, line=dict(color='grey', width=1), name='slowk_up_limit') - slowk_middle_limit = go.Scatter(x=data['ymd'], y=slowk_middle_limit, line=dict(color='grey', width=1), name='slowk_middle_limit') - slowk_down_limit = go.Scatter(x=data['ymd'], y=slowk_down_limit, line=dict(color='grey', width=1), name='slowk_down_limit') - - slowk_12 = go.Scatter(x=data['ymd'], y=data["slowk_12"], line=dict(color='#079118', width=2), name='slowk_12') - slowd_12 = go.Scatter(x=data['ymd'], y=data["slowd_12"], line=dict(dash='dashdot', color='#079118', width=2), name='slowd_12') - slowk_26 = go.Scatter(x=data['ymd'], y=data["slowk_26"], line=dict(color='grey', width=2), name='slowk_26') - slowd_26 = go.Scatter(x=data['ymd'], y=data["slowd_26"], line=dict(dash='dashdot', color='grey', width=2), name='slowd_26') - slowk_52 = go.Scatter(x=data['ymd'], y=data["slowk_52"], line=dict(color='#d755e8', width=2), name='slowk_52') - slowd_52 = go.Scatter(x=data['ymd'], y=data["slowd_52"], line=dict(dash='dashdot', color='#d755e8', width=2), name='slowd_52') - - - text_list = [] - for i in range(len(data['ymd'])): - text_list.append( - "{}

" - "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_avg60_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_avg60_diff'][i]), self.cz(data['laggingSpan_avg60_diff_rate'][i]), - self.cz(data['leadingSpan1_leadingSpan2_diff'][i]), self.cz(data['leadingSpan1_leadingSpan2_diff_rate'][i]) - )) - - candle_stick = go.Candlestick(x=data['ymd'], - open=data['open'], high=data['high'], low=data['low'], close=data['close'], - increasing_line_color='red', decreasing_line_color='blue', - name='candle', text=text_list, hoverinfo="text" - ) - - if bsLine is not None: - candle_data = [avg5, avg10, avg20, avg60, avg90, avg120, avg240, avg360, avg480, avg720, avg1440, avg2880, buy_check, sell_check, candle_stick, changeLine, baseLine, laggingSpan, leadingSpan1, leadingSpan2, upper_10_Line, lower_10_Line, middle_10_line, upper_20_Line, lower_20_Line, middle_20_line] - else: - candle_data = [avg5, avg10, avg20, avg60, avg90, avg120, avg240, avg360, avg480, avg720, avg1440, avg2880, candle_stick,changeLine, baseLine, laggingSpan, leadingSpan1, leadingSpan2] - - volume_data = [volume_line] - disparity_data = [laggingSpan_close_diff, laggingSpan_avg60_diff, leadingSpan1_leadingSpan2_diff] - loc_disparity_data = [laggingSpan_0_8_limit_line, laggingSpan_0_2_limit_line, laggingSpan_0_limit_line, laggingSpan__0_2_limit_line, laggingSpan__0_8_limit_line, - laggingSpan_close_diff_rate, laggingSpan_avg60_diff_rate, leadingSpan1_leadingSpan2_diff_rate, - loc_240_k, loc_240_d, loc_240_s, - new_high_9 ,new_high_26, new_low_9 ,new_low_26] - stochastic_data = [ - slowk_up_limit, slowk_middle_limit, slowk_down_limit, - slowk_12, slowd_12, - slowk_26, slowd_26, - slowk_52, slowd_52 - ] - # 그래프를 그린다. - """ - fig = go.Figure(data=candle_data) - fig.update_layout(title=stock_code) - fig.show() - """ - fig = subplots.make_subplots( - rows=5, cols=1, - subplot_titles=("이격도", "이격도 위치", "캔들", "slowkd", "거래량"), - shared_xaxes=True, horizontal_spacing=0.03, vertical_spacing=0.01, - row_heights=[200, 200, 700, 200, 200] - ) - for trace in disparity_data: - fig.append_trace(trace, 1, 1) - for trace in loc_disparity_data: - fig.append_trace(trace, 2, 1) - for trace in candle_data: - fig.append_trace(trace, 3, 1) - for trace in stochastic_data: - fig.append_trace(trace, 4, 1) - for trace in volume_data: - fig.append_trace(trace, 5, 1) - - #fig.update_xaxes(nticks=5) - #fig.update_layout(height=2400, title=stock_code, xaxis_rangeslider_visible=False) - - df = pd.DataFrame(bsLine) - df = df.fillna(-1) - - - buy_count = 0 - if bsLine is not None: - buy_count = len(df.loc[df["buy_price"] > 0]) - fig.update_layout(height=1400, - title="{}, buy: {}번 ".format(stock_code, buy_count), - xaxis_rangeslider_visible=False, - xaxis2_rangeslider_visible=False, - xaxis3_rangeslider_visible=False, - xaxis4_rangeslider_visible=False - ) - # 화면으로 출력함 - - return fig - - - def getPositionalEnergy(self, close): - # 260 (= 52 * 5)일 중 가장 찾은 금액과 가장 높았던 금액 중 현재가의 위치 계산 - - top = close[0] - bottom = close[0] - - for i in range(1, 260): - if i >= len(close): - break - if top < close[i]: - top = close[i] - if bottom > close[i]: - bottom = close[i] - - if top-close[0] == 0: - energy1 = 100.0 - else: - energy1 = round((close[0]-bottom) / (top-close[0]), 2) - - energy2 = round((close[0] / top), 2) - - return energy1, energy2 - - def writeSummary(self, param): - bull = list(param['bull']) - bear = list(param['bear']) - even = list(param['even']) - ymd = [i for i in range(len(bull))] - - bull_line = go.Scatter(x=ymd, y=bull, name="bull", line_color='#FF33A2') - bear_line = go.Scatter(x=ymd, y=bear, name="bear", line_color='#1469F4') - even_line = go.Scatter(x=ymd, y=even, name="even", line_color='#8B4513') - - line_data = [bull_line, bear_line, even_line] - - fig = subplots.make_subplots( - rows=1, cols=1, - subplot_titles=("주식 상황"), - shared_xaxes=True, horizontal_spacing=0.03, vertical_spacing=0.01, - row_heights=[800] - ) - for trace in line_data: - fig.append_trace(trace, 1, 1) - - fig.update_layout(height=810, xaxis_rangeslider_visible=False) - sum = param['bull'][0] + param['bear'][0] + param['even'][0] - title = "[Summary] bull: %d (%.2f), bear: %d (%.2f), even: %d (%.2f)" % (param['bull'][0], param['bull'][0]/sum, param['bear'][0], param['bear'][0]/sum, param['even'][0], param['even'][0]/sum) - fig['layout'].update(title=title) - - #fileName = "%s/summary.html" % (self.outPath) - #po.write_html(fig, file=fileName, auto_open=False) - - return - - def writeFile(self, outPath, CODE, NAME, top, stock, bsLine): - # 3년 이내 한번이라도 영업이익이 났는지 체크를 함 - fnguide = None - if CODE in self.fnguide: - fnguide = self.fnguide[CODE] - check = True - if fnguide: - check = False - for item in fnguide: - if item['business_profits'] > 0: - check = True - - if check: - fig = self.draw(CODE, stock, bsLine) - title = "%s (%s), 차트 (URL1, URL2, URL3)" % (NAME, CODE, CODE, CODE, CODE) - fig['layout'].update(title=title) - - fileName = outPath + "/%s_%s_%s_%s.html" % (datetime.today().strftime("%Y%m%d"), top, NAME.replace(" ", ""), CODE) - po.write_html(fig, file=fileName, auto_open=False) - return - - def checkVolume(self, p_volume, volume): - if 0 < p_volume <= 10000 and p_volume * 700 < volume: - return True - if 10000 < p_volume <= 50000 and p_volume * 40 < volume: - return True - if 50000 < p_volume <= 100000 and p_volume * 25 < volume: - return True - if 100000 < p_volume <= 200000 and p_volume * 15 < volume: - return True - if 200000 < p_volume <= 700000 and p_volume * 13 < volume: - return True - if 700000 < p_volume <= 1000000 and p_volume * 10 < volume: - return True - if 5000000 < p_volume <= 5000000 and p_volume * 5 < volume: - return True - if 5000000 < p_volume and p_volume * 4 < volume: - return True - return False - - def getStockData(self, CODE): - data_daily, ci_daily = self.jSDPattern.getData(CODE, ymd=(datetime.now()+timedelta(days=1)).strftime('%Y%m%d'), get_days=1500) - - return data_daily, ci_daily - - - def makeDir(self, dir_name): - if os.path.isdir(self.outPath + "/" + dir_name): - os.rmdir(self.outPath + "/" + dir_name) - os.mkdir(self.outPath + "/" + dir_name) - return - - def checkTransaction(self, ticker, data, ci): - # 어제 오늘 데이터로 분석 - bsLine = {} - - if data is not None and 'close' in data.columns: - size = len(data["close"]) - bsLine['buy_ymd'] = [None for i in range(size)] - bsLine['buy_price'] = [0 for i in range(size)] - bsLine['buy_count'] = [0 for i in range(size)] - bsLine['buy_type'] = ['' for i in range(size)] - bsLine['buy_cut'] = [None for i in range(size)] - bsLine['sell_price'] = [0 for i in range(size)] - bsLine['sell_count'] = [0 for i in range(size)] - bsLine['sell_type'] = ['' for i in range(size)] - bsLine['sell_cut'] = [0 for i in range(size)] - - size = ci - start = 0 - for i in range(start, size): - - # 매도 확인 - sell_price, sell_count, sell_type = self.buySell_Daily.getSellPrice(ticker, data, i, bsLine) - bsLine['sell_price'][i] = sell_price - bsLine['sell_count'][i] = sell_count - bsLine['sell_type'][i] = sell_type - bsLine['sell_cut'][i] = 0 - - if sell_price < 1: - buy_ymd, buy_price, buy_count, buy_type, buy_cut = self.buySell_Daily.getBuyPrice(ticker, data, i, bsLine) - - bsLine['buy_ymd'][i] = buy_ymd - bsLine['buy_price'][i] = buy_price - bsLine['buy_count'][i] = buy_count - bsLine['buy_type'][i] = buy_type - bsLine['buy_cut'][i] = buy_cut - - return bsLine - - - # 후보 찾기 - def findCandidates(self, outPath): - buy_stock_list = [] - - stockTableName = 'stock' - fnguideTableName = 'fnguide' - - conn = sqlite3.connect(self.stockFileName) - cursor = conn.cursor() - - cursor.execute('SELECT distinct code, name FROM ' + stockTableName + ' order by code') - #cursor.execute('select CODE, NAME, max(ymd) as ymd from ' + fnguideTableName + ' where type != "E" group by 1 order by total_assets desc') - items = cursor.fetchall() - - cursor.close() - conn.close() - - - for idx, item in enumerate(items): - CODE = item[0] - NAME = item[1] - ticker = {'ticker_code': CODE, 'ticker_name': NAME, 'unit': 0, 'MAX_BUY': 10000, 'BUY_INFO': {'buy_list': []}} - print("#", idx, ", CODE: ", CODE, ", NAME: ", NAME) - - stock_daily, ci = self.getStockData(CODE) - - bsLine = self.checkTransaction(ticker, stock_daily, ci) - - if bsLine['buy_ymd'][ci-1] is not None: - top = "0" - if CODE in self.topCompany: - top = str(self.topCompany[CODE][0]) - - # 거래량이 10만 이상이고, 종가가 1천원 이상인지 체크 (https://happpy-rich.tistory.com/94) - if stock_daily['volume'][ci-1] > 100000 and stock_daily['close'][ci-1] > 1000: - # 종목 상태 체크 분석 - - self.writeFile(outPath, CODE, NAME, top, stock_daily, bsLine) - buy_stock_list.append({'CODE': CODE, 'NAME': NAME}) - - buy_stock_str = '' - for i, item in enumerate(buy_stock_list): - buy_stock_str += str(i + 1) + ". " + item['CODE'] + "(" + item['NAME'] + ")\n" - self.bot.sendMsg("{}".format(buy_stock_str)) - - return - - -if __name__ == "__main__": - - start = time.time() - PROJECT_HOME = os.path.join(os.path.dirname(os.path.join(os.path.dirname(os.path.join(os.path.dirname(__file__)))))) - - RESOURCE_PATH = os.path.join(PROJECT_HOME, 'resources') - analyzerSqlite = AnalyzerSqlite(RESOURCE_PATH) - - - # HTML 출력 - outPath = os.path.join(PROJECT_HOME, "resources", "analysis") - if not os.path.isdir(outPath): - os.mkdir(outPath) - day = datetime.today().strftime("%Y%m%d") - before_7_day = datetime.today() + relativedelta(days=-7) - dayList = os.listdir(outPath) - for dayDir in dayList: - if dayDir[0] != '.' and dayDir < before_7_day.strftime("%Y%m%d"): - if os.path.exists(os.path.join(outPath, dayDir)) and os.path.isdir(os.path.join(outPath, dayDir)): - shutil.rmtree(os.path.join(outPath, dayDir)) - - outPath = os.path.join(outPath, day) - - if os.path.isdir(outPath): - shutil.rmtree(outPath) - os.mkdir(outPath) - print("print to Html...") - - analyzerSqlite.findCandidates(outPath) - - print("time : %6.2f 초" % (time.time() - start)) - print("done...") diff --git a/stock/analysis/JSDPattern.py b/stock/analysis/JSDPattern.py deleted file mode 100644 index d2951da..0000000 --- a/stock/analysis/JSDPattern.py +++ /dev/null @@ -1,571 +0,0 @@ -# https://bibot.tistory.com/63 -# https://nonmeyet.tistory.com/entry/Python-TALib%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B9%84%ED%8A%B8%EC%BD%94%EC%9D%B8%EC%A3%BC%EA%B0%80%EA%B8%B0%EC%88%A0%EB%B6%84%EC%84%9D-%EB%B3%B4%EC%A1%B0%EC%A7%80%ED%91%9C-%EC%B6%94%EA%B0%80 -# https://lunadaddy.tistory.com/122 -# https://wikidocs.net/186885 - -import os -import numpy as np -np.seterr(divide='ignore', invalid='ignore') -import sqlite3 -# https://www.lfd.uci.edu/~gohlke/pythonlibs/#ta-lib -# https://lunadaddy.tistory.com/122 -import talib -import pandas as pd -from datetime import datetime, timedelta - -from stock.analysis.IchimokuCloud import IchimokuCloud -from sklearn.preprocessing import StandardScaler - -class JSDPattern: - stockFileName = None - ichimokuCloud = None - scaler = None - - def __init__(self, stockFileName=None): - self.stockFileName = stockFileName - - self.ichimokuCloud = IchimokuCloud() - self.scaler = StandardScaler() - return - - def makeTickData(self, data, mins=1): - result = { - "ymd": [], - "open": [], "close": [], "high": [], "low": [], "volume": [], "volume_up": [], "volume_down": [], "volume_updown_diff": [] - } - - for i in range(mins, len(data['ymd'])+1, mins): - result["ymd"].append(data['ymd'][i-1]) - - result["open"].append(data['open'][i-mins]) - result["close"].append(data['close'][i-1]) - result["high"].append(max(data['high'][i - mins: i])) - result["low"].append(min(data['low'][i - mins: i])) - result["volume"].append(data['volume'][i-1]) - - if data['open'][i-1] < data['close'][i-1]: - result["volume_up"].append(data['volume'][i-1]) - result["volume_down"].append(0) - elif data['close'][i-1] < data['open'][i-1]: - result["volume_down"].append(-1*data['volume'][i-1]) - result["volume_up"].append(0) - else: - result["volume_up"].append(0) - result["volume_down"].append(0) - - up = [data['volume'][i - mins + c] for c in range(len(data['volume'][i - mins: i])) if data['close'][i - mins + c] < data['open'][i - mins + c]] - down = [data['volume'][i - mins + c] for c in range(len(data['volume'][i - mins: i])) if data['close'][i - mins + c] < data['open'][i - mins + c]] - result["volume_updown_diff"].append(sum(up) - sum(down)) - - return result - - def append(self, df=None, result=None): - data = { - "ymd": [], - "open": [], "close": [], "high": [], "low": [], "volume": [] - } - - if result is not None: - for i in range(len(result['ymd'])): - data['ymd'].append(result['ymd'][i]) - data['open'].append(result['open'][i]) - data['close'].append(result['close'][i]) - data['high'].append(result['high'][i]) - data['low'].append(result['low'][i]) - data['volume'].append(result['volume'][i]) - - if df is not None: - for i in range(len(df)): - data['ymd'].append(df.index[i]) - data['open'].append(df['open'][i]) - data['close'].append(df['close'][i]) - data['high'].append(df['high'][i]) - data['low'].append(df['low'][i]) - data['volume'].append(df['volume'][i]) - - return data - - def getDBData(self, stock_code, day, get_days=14): - - table = 'stock' - - conn = sqlite3.connect(self.stockFileName) - cursor = conn.cursor() - - result = {"ymd": [], "open": [], "close": [], "high": [], "low": [], "volume": []} - for i in range(get_days, -1, -1): - this_day = (datetime.strptime(day, '%Y%m%d') - timedelta(i)).strftime('%Y.%m.%d') - cursor.execute('SELECT ymd, open, high, low, close, volume FROM ' + table + ' WHERE CODE=? and ymd=? order by ymd', (stock_code, this_day,)) - - db_result = cursor.fetchall() - for rows in db_result: - ymd = datetime.strptime(rows[0], '%Y.%m.%d') # hts.날짜 - open = rows[1] # hts.시가 - high = rows[2] # hts.고가 - low = rows[3] # hts.저가 - close = rows[4] # hts.종가 - vol = rows[5] # hts.거래량 - - result["ymd"].append(ymd) - result["open"].append(float(open)) - result["close"].append(float(close)) - result["high"].append(float(high)) - result["low"].append(float(low)) - result["volume"].append(float(vol)) - - cursor.close() - conn.close() - - return result - - def getCoinData(self, ticker, ymd=None, get_days=14): - result = self.getDBData(ticker, ymd, get_days=get_days) - data = self.append(df=None, result=result) - - return data - - def is_Support(self, low, i, observation_time=5): - # https://sine-qua-none.tistory.com/198 - - # c1 = df.Low[i] < df.Low[i - 1] < df.Low[i - 2] < df.Low[i - 3] - # c2 = df.Low[i] < df.Low[i + 1] < df.Low[i + 2] < df.Low[i + 3] - # return c1 & c2 - - #if low[i] == np.min(low[i - 2*self.observation_time:i + 1]): - if low[i] == np.min(low[i - observation_time:i + observation_time + 1]): - return True - else: - return False - - def is_Resistance(self, high, i, observation_time=5): - # https://sine-qua-none.tistory.com/198 - - # c1 = df.High[i] > df.High[i - 1] > df.High[i - 2] > df.High[i - 3] - # c2 = df.High[i] > df.High[i + 1] > df.High[i + 2] > df.High[i + 3] - # return c1 & c2 - # if df['high'][i] == np.max(df['high'][i - self.observation_time:i + self.observation_time + 1]): - #if high[i] == np.max(high[i - 2*self.observation_time:i + 1]): - if high[i] == np.max(high[i - observation_time:i + observation_time + 1]): - return True - else: - return False - - - def getDiff_Rate(self, price1, price2, duration=1440, move=None): - # price1: close, price2: laggingSpan_27 - diff = [0 for i in range(len(price1))] - diff_rate = [0 for i in range(len(price1))] - - for i in range(0, len(price1)): - if price1[i] is not None and price2[i] is not None: - diff[i] = price1[i] - price2[i] - else: - diff[i] = None - - if len(price1) < duration: - duration = 52 - - for i in range(0, len(price1)): - - if duration <= i: - l = [d for d in diff[i - duration:i + 1] if d is not None and 0 < d] - if 0 < len(l): - min_v_p = np.min(l) - else: - min_v_p = 0 - l = [d for d in diff[i - duration:i + 1] if d is not None and 0 < d] - if 0 < len(l): - max_v_p = np.max(l) - else: - max_v_p = 0 - l = [d for d in diff[i - duration:i + 1] if d is not None and d < 0] - if 0 < len(l): - min_v_m = np.min(l) - else: - min_v_m = 0 - l = [d for d in diff[i - duration:i + 1] if d is not None and d < 0] - if 0 < len(l): - max_v_m = np.max(l) - else: - max_v_m = 0 - - if diff[i] is not None: - if 0 <= diff[i]: - if max_v_p - min_v_p == 0: - diff_rate[i] = 0 - else: - diff_rate[i] = (diff[i] - min_v_p) / (max_v_p - min_v_p) - else: - if max_v_m - min_v_m == 0: - diff_rate[i] = 0 - else: - diff_rate[i] = ((diff[i] - min_v_m) / (max_v_m - min_v_m)) - 1 - else: - diff_rate[i] = None - - return diff, diff_rate - - def analyze(self, result, mins=1): - result["volume"] = [result["volume"][i] if 0 < result["volume"][i] else 1 for i in range(len(result["volume"]))] - # 기본 캔들 정보 - open_df = pd.DataFrame(result["open"]) - close_df = pd.DataFrame(result["close"]) - high_df = pd.DataFrame(result["high"]) - low_df = pd.DataFrame(result["low"]) - volume_df = pd.DataFrame(result["volume"]) - - # 중복 제거 - ymd_df = pd.DataFrame(result["ymd"]) - data_dup = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1) - data_dup.columns = ["ymd", "open", "close", "high", "low", "volume"] - data_dup.index = pd.DatetimeIndex(result["ymd"]) - data_dup_sorted = data_dup.sort_index(ascending=True) - data_dup_sorted = data_dup_sorted.drop_duplicates() - - ymd_df = data_dup_sorted["ymd"] - open_df = data_dup_sorted["open"] - close_df = data_dup_sorted["close"] - high_df = data_dup_sorted["high"] - low_df = data_dup_sorted["low"] - volume_df = data_dup_sorted["volume"] - - ymd = ymd_df.tolist() - open = open_df.tolist() - close = close_df.tolist() - high = high_df.tolist() - low = low_df.tolist() - volume = volume_df.tolist() - - # ichimokuCloud - df = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1) - column_names = ['DATE', 'open', 'close', 'high', 'low', 'volume'] - df.columns = column_names - c, b, l, s = 9, 26, 52, 26 - # 1. 전환선 = (과거 9일 동안 최고가 + 최저가) / 2 - # 당일을 포함한 9일 동안의 최고가와 최저가의 중간 값을 평균으로 나타낸다. - changeLine = (df.high.rolling(c).max() + df.low.rolling(c).min()) / 2 - # 2. 기준선 = 과거 26일 동안 최고가 + 최저가) / 2 - # 당일을 포함한 26일 동안의 최고가와 최저가의 중간 값을 평균으로 나타낸다. - baseLine = (df.high.rolling(b).max() + df.low.rolling(b).min()) / 2 - - # 3. 후행스팬 = 현재 close가격의 26일전 반영 - laggingSpan = [df.close.values[i + s] for i in range(len(df.close) - s)] - laggingSpan += [None for i in range(s)] - laggingSpan = np.array(laggingSpan) - - # 4. 선행스팬 1 = ((기준선 + 전환선) / 2)를 26일 선행하여 배치 - # 전환선과 기준선의 평균값을 구해 당일 포함 26일 앞으로 이동시킨 선 (중-단기 구간의 힘을 보여줌) - tmp_leadingSpan1 = (changeLine + baseLine) / 2 - """ S: 26일 선행시킴 """ - leadingSpan1 = list(tmp_leadingSpan1.values) - for i in range(b - 1): - leadingSpan1.insert(0, None) - """ E: 26일 선행시킴 """ - - # 5. 선행스팬 2 = ((최근 52일 동안 최고가 + 최저가) / 2)를 26일 선행하여 배치 - # 당일을 포함한 52일 동안의 최고가와 최저가의 평균을 26일 앞으로 이동시킨 선 (장기으로 형성된 선이기 때문에 가장 느리게 변함) - tmp_leadingSpan2 = (df.high.rolling(l).max() + df.low.rolling(l).min()) / 2 - """ S: 52일 선행시킴 """ - leadingSpan2 = list(tmp_leadingSpan2.values) - for i in range(l - 1): - leadingSpan2.insert(0, None) - """ S: 52일 선행시킴 """ - - baseLine = baseLine.tolist() - changeLine = changeLine.tolist() - laggingSpan = list(laggingSpan) - current_index = len(ymd) - for i in range(51): - if len(ymd) < len(leadingSpan2): - if mins==1440: - ymd.append(ymd[-1] + timedelta(days=1)) - else: - ymd.append(ymd[-1] + timedelta(minutes=1)) - if len(open) < len(leadingSpan2): - open.append(None) - if len(close) < len(leadingSpan2): - close.append(None) - if len(high) < len(leadingSpan2): - high.append(None) - if len(low) < len(leadingSpan2): - low.append(None) - if len(volume) < len(leadingSpan2): - volume.append(None) - if len(baseLine) < len(leadingSpan2): - baseLine.append(None) - if len(changeLine) < len(leadingSpan2): - changeLine.append(None) - if len(laggingSpan) < len(leadingSpan2): - laggingSpan.append(None) - for i in range(26): - if len(leadingSpan1) < len(leadingSpan2): - leadingSpan1.append(leadingSpan1[-1]) - - # 9일 신고가 - new_high_9 = [0 for c in range(8)] + [1 if (changeLine[c-1] is not None and changeLine[c] is not None and changeLine[c-1] < changeLine[c]) and None not in close[c-8:c+1] and max(close[c-8:c]) < close[c] else 0 for c in range(8, len(close))] - # 26일 신고가 - new_high_26 = [0 for c in range(25)] + [1 if (baseLine[c-1] is not None and baseLine[c] is not None and baseLine[c-1] < baseLine[c]) and None not in close[c-8:c+1] and max(close[c-25:c]) < close[c] else 0 for c in range(25, len(close))] - # 33일 신고가 - new_high_33 = [0 for c in range(32)] + [1 if (leadingSpan1[c-1] is not None and leadingSpan1[c] is not None and leadingSpan1[c-1] < leadingSpan1[c]) and None not in close[c-8:c+1] and max(close[c-32:c]) < close[c] else 0 for c in range(32, len(close))] - # 52일 신고가 - new_high_52 = [0 for c in range(51)] + [1 if (leadingSpan2[c-1] is not None and leadingSpan2[c] is not None and leadingSpan2[c-1] < leadingSpan2[c]) and None not in close[c-8:c+1] and max(close[c-51:c]) < close[c] else 0 for c in range(51, len(close))] - - # 9일 신저가 - new_low_9 = [0 for c in range(8)] + [1 if (changeLine[c-1] is not None and changeLine[c] is not None and changeLine[c-1] < changeLine[c]) and None not in close[c-8:c+1] and close[c-9] < min(close[c-8:c+1]) else 0 for c in range(8, len(close))] - # 26일 신저가 - new_low_26 = [0 for c in range(25)] + [1 if (baseLine[c-1] is not None and baseLine[c] is not None and baseLine[c-1] < baseLine[c]) and None not in close[c-8:c+1] and close[c-26] < min(close[c-25:c+1]) else 0 for c in range(25, len(close))] - # 33일 신저가 - new_low_33 = [0 for c in range(32)] + [1 if (leadingSpan1[c-1] is not None and leadingSpan1[c] is not None and leadingSpan1[c-1] < leadingSpan1[c]) and None not in close[c-8:c+1] and close[c-33] < min(close[c-32:c+1]) else 0 for c in range(32, len(close))] - # 52일 신저가 - new_low_52 = [0 for c in range(51)] + [1 if (leadingSpan2[c-1] is not None and leadingSpan2[c] is not None and leadingSpan2[c-1] < leadingSpan2[c]) and None not in close[c-8:c+1] and close[c-52] < min(close[c-51:c+1]) else 0 for c in range(51, len(close))] - - - # 이동 평균 - close_df = pd.DataFrame(close) - avg5 = list(np.reshape(close_df.ewm(5).mean().values, -1)) - avg10 = list(np.reshape(close_df.ewm(10).mean().values, -1)) - avg20 = list(np.reshape(close_df.ewm(20).mean().values, -1)) - avg60 = list(np.reshape(close_df.ewm(60).mean().values, -1)) - avg90 = list(np.reshape(close_df.ewm(90).mean().values, -1)) - avg120 = list(np.reshape(close_df.ewm(120).mean().values, -1)) - avg240 = list(np.reshape(close_df.ewm(240).mean().values, -1)) - avg360 = list(np.reshape(close_df.ewm(360).mean().values, -1)) - avg480 = list(np.reshape(close_df.ewm(480).mean().values, -1)) - avg720 = list(np.reshape(close_df.ewm(720).mean().values, -1)) - avg1440 = list(np.reshape(close_df.ewm(1440).mean().values, -1)) - avg2880 = list(np.reshape(close_df.ewm(2880).mean().values, -1)) - - np_high, np_low, np_close = np.array(high, dtype=np.float64), np.array(low, dtype=np.float64), np.array(close, dtype=np.float64) - slowk_12_df, slowd_12_df = talib.STOCH(np_high, np_low, np_close, fastk_period=12, slowk_period=5, slowk_matype=0, slowd_period=5, slowd_matype=0) - slowk_26_df, slowd_26_df = talib.STOCH(np_high, np_low, np_close, fastk_period=26, slowk_period=16, slowk_matype=0, slowd_period=16, slowd_matype=0) - slowk_52_df, slowd_52_df = talib.STOCH(np_high, np_low, np_close, fastk_period=52, slowk_period=32, slowk_matype=0, slowd_period=32, slowd_matype=0) - - - # 최고/최저 위치 - loc_240 = [None for i in range(len(close))] - for i in range(240, len(close)): - min_v = np.min(result["close"][i-239:i+1]) - max_v = np.max(result["close"][i-239:i+1]) - if close[i] is not None: - loc_240[i] = ((close[i] - min_v) / (max_v - min_v)) - else: - loc_240[i] = None - - loc_240 = pd.DataFrame(loc_240) - loc_240_k = loc_240.to_numpy().reshape(-1) - loc_240_d = loc_240.rolling(20).mean() - loc_240_s = loc_240.rolling(60).mean() - loc_240_d = loc_240_d.to_numpy().reshape(-1) - loc_240_s = loc_240_s.to_numpy().reshape(-1) - - # 볼린저 밴드 - n, t = 10, 2 - max_10 = close_df.rolling(window=n).mean() - stddev_10 = close_df.rolling(window=n).std() - upper_10 = max_10 + (stddev_10 * t) # 상단 볼리저 밴드 - lower_10 = max_10 - (stddev_10 * t) # 하단 볼리저 밴드 - middle_10 = (upper_10 + lower_10) / 2 - upper_10 = list(np.reshape(upper_10.values, -1)) - lower_10 = list(np.reshape(lower_10.values, -1)) - middle_10 = list(np.reshape(middle_10.values, -1)) - - n, t = 20, 2 - max_20 = close_df.rolling(window=n).mean() - stddev_20 = close_df.rolling(window=n).std() - upper_20 = max_20 + (stddev_20 * t) # 상단 볼리저 밴드 - lower_20 = max_20 - (stddev_20 * t) # 하단 볼리저 밴드 - middle_20 = (upper_20 + lower_20) / 2 - upper_20 = list(np.reshape(upper_20.values, -1)) - lower_20 = list(np.reshape(lower_20.values, -1)) - middle_20 = list(np.reshape(middle_20.values, -1)) - - duration = 1440 - if mins == 1440: - duration = 360 - laggingSpan_close_diff, laggingSpan_close_diff_rate = self.getDiff_Rate(laggingSpan, close, duration=duration) - laggingSpan_changeLine_diff, laggingSpan_changeLine_diff_rate = self.getDiff_Rate(laggingSpan, changeLine, duration=duration) - laggingSpan_baseLine_diff, laggingSpan_baseLine_diff_rate = self.getDiff_Rate(laggingSpan, baseLine, duration=duration) - laggingSpan_leadingSpan1_diff, laggingSpan_leadingSpan1_diff_rate = self.getDiff_Rate(laggingSpan, leadingSpan1, duration=duration) - laggingSpan_leadingSpan2_diff, laggingSpan_leadingSpan2_diff_rate = self.getDiff_Rate(laggingSpan, leadingSpan2, duration=duration) - laggingSpan_avg60_diff, laggingSpan_avg60_diff_rate = self.getDiff_Rate(laggingSpan, avg60, duration=duration) - laggingSpan_lower10_diff, laggingSpan_lower10_diff_rate = self.getDiff_Rate(laggingSpan, lower_10, duration=duration) - laggingSpan_middle10_diff, laggingSpan_middle10_diff_rate = self.getDiff_Rate(laggingSpan, middle_10, duration=duration) - laggingSpan_upper10_diff, laggingSpan_upper10_diff_rate = self.getDiff_Rate(laggingSpan, upper_10, duration=duration) - laggingSpan_lower20_diff, laggingSpan_lower20_diff_rate = self.getDiff_Rate(laggingSpan, lower_20, duration=duration) - laggingSpan_middle20_diff, laggingSpan_middle20_diff_rate = self.getDiff_Rate(laggingSpan, middle_20, duration=duration) - laggingSpan_upper20_diff, laggingSpan_upper20_diff_rate = self.getDiff_Rate(laggingSpan, upper_20, duration=duration) - baseLine_close_diff, baseLine_close_diff_rate = self.getDiff_Rate(baseLine, close, duration=duration) - changeLine_close_diff, changeLine_close_diff_rate = self.getDiff_Rate(changeLine, close, duration=duration) - changeLine_baseLine_diff, changeLine_baseLine_diff_rate = self.getDiff_Rate(changeLine, baseLine, duration=duration) - changeLine_leadingSpan1_diff, changeLine_leadingSpan1_diff_rate = self.getDiff_Rate(changeLine, leadingSpan1, duration=duration) - leadingSpan1_leadingSpan2_diff, leadingSpan1_leadingSpan2_diff_rate = self.getDiff_Rate(leadingSpan1, leadingSpan2, duration=duration) - - - df_list = [ - pd.DataFrame(ymd), - pd.DataFrame(open), pd.DataFrame(close), pd.DataFrame(high), pd.DataFrame(low), pd.DataFrame(volume), - pd.DataFrame(changeLine), pd.DataFrame(baseLine), pd.DataFrame(laggingSpan), pd.DataFrame(leadingSpan1), pd.DataFrame(leadingSpan2), - - pd.DataFrame(laggingSpan_close_diff), - pd.DataFrame(laggingSpan_changeLine_diff), - pd.DataFrame(laggingSpan_baseLine_diff), - pd.DataFrame(laggingSpan_leadingSpan1_diff), - pd.DataFrame(laggingSpan_leadingSpan2_diff), - pd.DataFrame(laggingSpan_avg60_diff), - pd.DataFrame(laggingSpan_lower10_diff), - pd.DataFrame(laggingSpan_middle10_diff), - pd.DataFrame(laggingSpan_upper10_diff), - pd.DataFrame(laggingSpan_lower20_diff), - pd.DataFrame(laggingSpan_middle20_diff), - pd.DataFrame(laggingSpan_upper20_diff), - pd.DataFrame(baseLine_close_diff), - pd.DataFrame(changeLine_close_diff), - pd.DataFrame(changeLine_baseLine_diff), - pd.DataFrame(changeLine_leadingSpan1_diff), - pd.DataFrame(leadingSpan1_leadingSpan2_diff), - - pd.DataFrame(laggingSpan_close_diff_rate), - pd.DataFrame(laggingSpan_changeLine_diff_rate), - pd.DataFrame(laggingSpan_baseLine_diff_rate), - pd.DataFrame(laggingSpan_leadingSpan1_diff_rate), - pd.DataFrame(laggingSpan_leadingSpan2_diff_rate), - pd.DataFrame(laggingSpan_avg60_diff_rate), - pd.DataFrame(laggingSpan_lower10_diff_rate), - pd.DataFrame(laggingSpan_middle10_diff_rate), - pd.DataFrame(laggingSpan_upper10_diff_rate), - pd.DataFrame(laggingSpan_lower20_diff_rate), - pd.DataFrame(laggingSpan_middle20_diff_rate), - pd.DataFrame(laggingSpan_upper20_diff_rate), - pd.DataFrame(baseLine_close_diff_rate), - pd.DataFrame(changeLine_close_diff_rate), - pd.DataFrame(changeLine_baseLine_diff_rate), - pd.DataFrame(changeLine_leadingSpan1_diff_rate), - pd.DataFrame(leadingSpan1_leadingSpan2_diff_rate), - - pd.DataFrame(loc_240_k), pd.DataFrame(loc_240_d), pd.DataFrame(loc_240_s), - - pd.DataFrame(avg5), pd.DataFrame(avg10), pd.DataFrame(avg20), pd.DataFrame(avg60), pd.DataFrame(avg90), pd.DataFrame(avg120), pd.DataFrame(avg240), pd.DataFrame(avg360), pd.DataFrame(avg480), pd.DataFrame(avg720), pd.DataFrame(avg1440), pd.DataFrame(avg2880), - pd.DataFrame(upper_10), pd.DataFrame(lower_10), pd.DataFrame(middle_10), - pd.DataFrame(upper_20), pd.DataFrame(lower_20), pd.DataFrame(middle_20), - - pd.DataFrame(new_high_9), pd.DataFrame(new_high_26), pd.DataFrame(new_high_33), pd.DataFrame(new_high_52), - pd.DataFrame(new_low_9), pd.DataFrame(new_low_26), pd.DataFrame(new_low_33), pd.DataFrame(new_low_52), - pd.DataFrame(slowk_12_df), pd.DataFrame(slowd_12_df), - pd.DataFrame(slowk_26_df), pd.DataFrame(slowd_26_df), - pd.DataFrame(slowk_52_df), pd.DataFrame(slowd_52_df), - - ] - - data = pd.concat(df_list, axis=1) - column_names = [ - 'ymd', - 'open', 'close', 'high', 'low', 'volume', - 'changeLine', 'baseLine', 'laggingSpan', 'leadingSpan1', 'leadingSpan2', - - 'laggingSpan_close_diff', - 'laggingSpan_changeLine_diff', - 'laggingSpan_baseLine_diff', - 'laggingSpan_leadingSpan1_diff', - 'laggingSpan_leadingSpan2_diff', - 'laggingSpan_avg60_diff', - 'laggingSpan_lower10_diff', - 'laggingSpan_middle10_diff', - 'laggingSpan_upper10_diff', - 'laggingSpan_lower20_diff', - 'laggingSpan_middle20_diff', - 'laggingSpan_upper20_diff', - 'baseLine_close_diff', - 'changeLine_close_diff', - 'changeLine_baseLine_diff', - 'changeLine_leadingSpan1_diff', - 'leadingSpan1_leadingSpan2_diff', - - 'laggingSpan_close_diff_rate', - 'laggingSpan_changeLine_diff_rate', - 'laggingSpan_baseLine_diff_rate', - 'laggingSpan_leadingSpan1_diff_rate', - 'laggingSpan_leadingSpan2_diff_rate', - 'laggingSpan_avg60_diff_rate', - 'laggingSpan_lower10_diff_rate', - 'laggingSpan_middle10_diff_rate', - 'laggingSpan_upper10_diff_rate', - 'laggingSpan_lower20_diff_rate', - 'laggingSpan_middle20_diff_rate', - 'laggingSpan_upper20_diff_rate', - 'baseLine_close_diff_rate', - 'changeLine_close_diff_rate', - 'changeLine_baseLine_diff_rate', - 'changeLine_leadingSpan1_diff_rate', - 'leadingSpan1_leadingSpan2_diff_rate', - - 'loc_240_k', 'loc_240_d', 'loc_240_s', - - 'avg5', 'avg10', 'avg20', 'avg60', 'avg90', 'avg120', 'avg240', 'avg360', 'avg480', 'avg720', 'avg1440', 'avg2880', - - 'upper_10', 'lower_10', 'middle_10', - 'upper_20', 'lower_20', 'middle_20', - - 'new_high_9', 'new_high_26', 'new_high_33', 'new_high_52', - 'new_low_9', 'new_low_26', 'new_low_33', 'new_low_52', - - 'slowk_12', 'slowd_12', - 'slowk_26', 'slowd_26', - 'slowk_52', 'slowd_52', - ] - data.columns = column_names - data.index = pd.DatetimeIndex(ymd) - - return data, current_index - - def getData(self, ticker, mins=None, ymd=None, get_days=14): - if ymd is None: - result = self.getCoinData(ticker, mins=mins, get_days=get_days) - else: - result = self.getCoinData(ticker, mins=mins, ymd=ymd, get_days=get_days) - - if len(result['ymd']) < 1: - return None, None - - #result_tic = self.makeTickData(result_m1, mins=minute) - data, current_index = self.analyze(result, mins=mins) - return data, current_index - - def analyzePattern(self, data): - # jSDPattern.analyzePattern(data) - - data = data[['open', 'high', 'low', 'close', 'volume']].astype(float) - pattern_names = talib.get_function_groups()['Pattern Recognition'] - pattern_results = {} - for pattern in pattern_names: - pattern_function = getattr(talib, pattern) - result = pattern_function(data['open'].values, data['high'].values, data['low'].values, data['close'].values) - if result[-1] != 0: - pattern_results[pattern] = result[-1] - - if len(pattern_results) > 0: - for pattern, result in pattern_results.items(): - if result > 0: - direction = "상승" - else: - direction = "하락" - print(f"{pattern}: {direction}") - else: - print("인식된 차트 패턴이 없습니다.") - - return - -if __name__ == "__main__": - def min_max_normalize(data): - min_val = min(data) - max_val = max(data) - normalized_data = [(x - min_val) / (max_val - min_val) for x in data] - return normalized_data - - - # 예시 데이터 - original_data = [-4, -3, -2, -1, 0] - normalized_data = min_max_normalize(original_data) - print(np.asarray(normalized_data)-1) - original_data = [0, 2,4,6,8,10] - normalized_data = min_max_normalize(original_data) - print(normalized_data) \ No newline at end of file diff --git a/stock/analysis/JSDPattern_realtime.py b/stock/analysis/JSDPattern_realtime.py deleted file mode 100644 index bf36d77..0000000 --- a/stock/analysis/JSDPattern_realtime.py +++ /dev/null @@ -1,255 +0,0 @@ -# https://bibot.tistory.com/63 -# https://nonmeyet.tistory.com/entry/Python-TALib%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B9%84%ED%8A%B8%EC%BD%94%EC%9D%B8%EC%A3%BC%EA%B0%80%EA%B8%B0%EC%88%A0%EB%B6%84%EC%84%9D-%EB%B3%B4%EC%A1%B0%EC%A7%80%ED%91%9C-%EC%B6%94%EA%B0%80 -# https://lunadaddy.tistory.com/122 -# https://wikidocs.net/186885 - -import os -from scipy.signal import savgol_filter -import numpy as np -np.seterr(divide='ignore', invalid='ignore') -# https://www.lfd.uci.edu/~gohlke/pythonlibs/#ta-lib -# https://lunadaddy.tistory.com/122 -import talib -import pandas as pd -from datetime import datetime, timedelta - -from stock.analysis.JSDPattern import JSDPattern - -class JSDPattern_realtime (JSDPattern): - - def __init__(self, stockFileName=None): - super().__init__(stockFileName) - return - - def analyze(self, result): - result["volume"] = [result["volume"][i] if 0 < result["volume"][i] else 1 for i in range(len(result["volume"]))] - # 기본 캔들 정보 - open_df = pd.DataFrame(result["open"]) - close_df = pd.DataFrame(result["close"]) - high_df = pd.DataFrame(result["high"]) - low_df = pd.DataFrame(result["low"]) - volume_df = pd.DataFrame(result["volume"]) - - # 중복 제거 - ymd_df = pd.DataFrame(result["ymd"]) - data_dup = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1) - data_dup.columns = ["ymd", "open", "close", "high", "low", "volume"] - data_dup.index = pd.DatetimeIndex(result["ymd"]) - data_dup_sorted = data_dup.sort_index(ascending=True) - data_dup_sorted = data_dup_sorted.drop_duplicates() - - ymd_df = data_dup_sorted["ymd"] - open_df = data_dup_sorted["open"] - close_df = data_dup_sorted["close"] - high_df = data_dup_sorted["high"] - low_df = data_dup_sorted["low"] - volume_df = data_dup_sorted["volume"] - - ymd = ymd_df.tolist() - open = open_df.tolist() - close = close_df.tolist() - high = high_df.tolist() - low = low_df.tolist() - volume = volume_df.tolist() - - # ichimokuCloud - df = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1) - column_names = ['DATE', 'open', 'close', 'high', 'low', 'volume'] - df.columns = column_names - c, b, l, s = 9, 26, 52, 26 - # 1. 전환선 = (과거 9일 동안 최고가 + 최저가) / 2 - # 당일을 포함한 9일 동안의 최고가와 최저가의 중간 값을 평균으로 나타낸다. - changeLine = (df.high.rolling(c).max() + df.low.rolling(c).min()) / 2 - # 2. 기준선 = 과거 26일 동안 최고가 + 최저가) / 2 - # 당일을 포함한 26일 동안의 최고가와 최저가의 중간 값을 평균으로 나타낸다. - baseLine = (df.high.rolling(b).max() + df.low.rolling(b).min()) / 2 - - # 3. 후행스팬 = 현재 close가격의 26일전 반영 - laggingSpan = [df.close.values[i + s] for i in range(len(df.close) - s)] - laggingSpan += [None for i in range(s)] - laggingSpan = np.array(laggingSpan) - - # 4. 선행스팬 1 = ((기준선 + 전환선) / 2)를 26일 선행하여 배치 - # 전환선과 기준선의 평균값을 구해 당일 포함 26일 앞으로 이동시킨 선 (중-단기 구간의 힘을 보여줌) - tmp_leadingSpan1 = (changeLine + baseLine) / 2 - """ S: 26일 선행시킴 """ - leadingSpan1 = list(tmp_leadingSpan1.values) - for i in range(b - 1): - leadingSpan1.insert(0, None) - """ E: 26일 선행시킴 """ - - # 5. 선행스팬 2 = ((최근 52일 동안 최고가 + 최저가) / 2)를 26일 선행하여 배치 - # 당일을 포함한 52일 동안의 최고가와 최저가의 평균을 26일 앞으로 이동시킨 선 (장기으로 형성된 선이기 때문에 가장 느리게 변함) - tmp_leadingSpan2 = (df.high.rolling(l).max() + df.low.rolling(l).min()) / 2 - """ S: 52일 선행시킴 """ - leadingSpan2 = list(tmp_leadingSpan2.values) - for i in range(l - 1): - leadingSpan2.insert(0, None) - """ S: 52일 선행시킴 """ - - baseLine = baseLine.tolist() - changeLine = changeLine.tolist() - laggingSpan = list(laggingSpan) - current_index = len(ymd) - for i in range(51): - if len(ymd) < len(leadingSpan2): - ymd.append(ymd[-1] + timedelta(days=1)) - if len(open) < len(leadingSpan2): - open.append(None) - if len(close) < len(leadingSpan2): - close.append(None) - if len(high) < len(leadingSpan2): - high.append(None) - if len(low) < len(leadingSpan2): - low.append(None) - if len(volume) < len(leadingSpan2): - volume.append(None) - if len(baseLine) < len(leadingSpan2): - baseLine.append(None) - if len(changeLine) < len(leadingSpan2): - changeLine.append(None) - if len(laggingSpan) < len(leadingSpan2): - laggingSpan.append(None) - for i in range(26): - if len(leadingSpan1) < len(leadingSpan2): - leadingSpan1.append(leadingSpan1[-1]) - - # 9일 신고가 - new_high_9 = [0 for c in range(8)] + [1 if (changeLine[c-1] is not None and changeLine[c] is not None and changeLine[c-1] < changeLine[c]) and None not in close[c-8:c+1] and max(close[c-8:c]) < close[c] else 0 for c in range(8, len(close))] - # 26일 신고가 - new_high_26 = [0 for c in range(25)] + [1 if (baseLine[c-1] is not None and baseLine[c] is not None and baseLine[c-1] < baseLine[c]) and None not in close[c-8:c+1] and max(close[c-25:c]) < close[c] else 0 for c in range(25, len(close))] - - # 9일 신저가 - new_low_9 = [0 for c in range(8)] + [1 if (changeLine[c-1] is not None and changeLine[c] is not None and changeLine[c-1] < changeLine[c]) and None not in close[c-8:c+1] and close[c-9] < min(close[c-8:c+1]) else 0 for c in range(8, len(close))] - # 26일 신저가 - new_low_26 = [0 for c in range(25)] + [1 if (baseLine[c-1] is not None and baseLine[c] is not None and baseLine[c-1] < baseLine[c]) and None not in close[c-8:c+1] and close[c-26] < min(close[c-25:c+1]) else 0 for c in range(25, len(close))] - - - # 이동 평균 - close_df = pd.DataFrame(close) - avg5 = list(np.reshape(close_df.ewm(5).mean().values, -1)) - avg10 = list(np.reshape(close_df.ewm(10).mean().values, -1)) - avg20 = list(np.reshape(close_df.ewm(20).mean().values, -1)) - avg60 = list(np.reshape(close_df.ewm(60).mean().values, -1)) - avg90 = list(np.reshape(close_df.ewm(90).mean().values, -1)) - avg120 = list(np.reshape(close_df.ewm(120).mean().values, -1)) - avg240 = list(np.reshape(close_df.ewm(240).mean().values, -1)) - avg360 = list(np.reshape(close_df.ewm(360).mean().values, -1)) - avg480 = list(np.reshape(close_df.ewm(480).mean().values, -1)) - - np_high, np_low, np_close = np.array(high, dtype=np.float64), np.array(low, dtype=np.float64), np.array(close, dtype=np.float64) - slowk_12_df, slowd_12_df = talib.STOCH(np_high, np_low, np_close, fastk_period=12, slowk_period=5, slowk_matype=0, slowd_period=5, slowd_matype=0) - slowk_26_df, slowd_26_df = talib.STOCH(np_high, np_low, np_close, fastk_period=26, slowk_period=16, slowk_matype=0, slowd_period=16, slowd_matype=0) - slowk_52_df, slowd_52_df = talib.STOCH(np_high, np_low, np_close, fastk_period=52, slowk_period=32, slowk_matype=0, slowd_period=32, slowd_matype=0) - - - # 볼린저 밴드 - n, t = 10, 2 - max_10 = close_df.rolling(window=n).mean() - stddev_10 = close_df.rolling(window=n).std() - upper_10 = max_10 + (stddev_10 * t) # 상단 볼리저 밴드 - lower_10 = max_10 - (stddev_10 * t) # 하단 볼리저 밴드 - middle_10 = (upper_10 + lower_10) / 2 - upper_10 = list(np.reshape(upper_10.values, -1)) - lower_10 = list(np.reshape(lower_10.values, -1)) - middle_10 = list(np.reshape(middle_10.values, -1)) - - n, t = 20, 2 - max_20 = close_df.rolling(window=n).mean() - stddev_20 = close_df.rolling(window=n).std() - upper_20 = max_20 + (stddev_20 * t) # 상단 볼리저 밴드 - lower_20 = max_20 - (stddev_20 * t) # 하단 볼리저 밴드 - middle_20 = (upper_20 + lower_20) / 2 - upper_20 = list(np.reshape(upper_20.values, -1)) - lower_20 = list(np.reshape(lower_20.values, -1)) - middle_20 = list(np.reshape(middle_20.values, -1)) - - duration = 360 - laggingSpan_close_diff, laggingSpan_close_diff_rate = self.getDiff_Rate(laggingSpan, close, duration=duration) - laggingSpan_avg60_diff, laggingSpan_avg60_diff_rate = self.getDiff_Rate(laggingSpan, avg60, duration=duration) - leadingSpan1_leadingSpan2_diff, leadingSpan1_leadingSpan2_diff_rate = self.getDiff_Rate(leadingSpan1, leadingSpan2, duration=duration) - - df_list = [ - pd.DataFrame(ymd), - pd.DataFrame(open), pd.DataFrame(close), pd.DataFrame(high), pd.DataFrame(low), pd.DataFrame(volume), - pd.DataFrame(changeLine), pd.DataFrame(baseLine), pd.DataFrame(laggingSpan), pd.DataFrame(leadingSpan1), pd.DataFrame(leadingSpan2), - - pd.DataFrame(laggingSpan_close_diff), - pd.DataFrame(laggingSpan_avg60_diff), - pd.DataFrame(leadingSpan1_leadingSpan2_diff), - - pd.DataFrame(laggingSpan_close_diff_rate), - pd.DataFrame(laggingSpan_avg60_diff_rate), - pd.DataFrame(leadingSpan1_leadingSpan2_diff_rate), - - pd.DataFrame(avg5), pd.DataFrame(avg10), pd.DataFrame(avg20), pd.DataFrame(avg60), pd.DataFrame(avg90), pd.DataFrame(avg120), pd.DataFrame(avg240), pd.DataFrame(avg360), pd.DataFrame(avg480), - pd.DataFrame(upper_10), pd.DataFrame(lower_10), pd.DataFrame(middle_10), - pd.DataFrame(upper_20), pd.DataFrame(lower_20), pd.DataFrame(middle_20), - - pd.DataFrame(new_high_9), pd.DataFrame(new_high_26), - pd.DataFrame(new_low_9), pd.DataFrame(new_low_26), - pd.DataFrame(slowk_12_df), pd.DataFrame(slowd_12_df), - pd.DataFrame(slowk_26_df), pd.DataFrame(slowd_26_df), - pd.DataFrame(slowk_52_df), pd.DataFrame(slowd_52_df), - - ] - - data = pd.concat(df_list, axis=1) - column_names = [ - 'ymd', - 'open', 'close', 'high', 'low', 'volume', - 'changeLine', 'baseLine', 'laggingSpan', 'leadingSpan1', 'leadingSpan2', - - 'laggingSpan_close_diff', - 'laggingSpan_avg60_diff', - 'leadingSpan1_leadingSpan2_diff', - - 'laggingSpan_close_diff_rate', - 'laggingSpan_avg60_diff_rate', - 'leadingSpan1_leadingSpan2_diff_rate', - - 'avg5', 'avg10', 'avg20', 'avg60', 'avg90', 'avg120', 'avg240', 'avg360', 'avg480', - - 'upper_10', 'lower_10', 'middle_10', - 'upper_20', 'lower_20', 'middle_20', - - 'new_high_9', 'new_high_26', - 'new_low_9', 'new_low_26', - - 'slowk_12', 'slowd_12', - 'slowk_26', 'slowd_26', - 'slowk_52', 'slowd_52', - ] - data.columns = column_names - data.index = pd.DatetimeIndex(ymd) - - return data, current_index - - def getData(self, ticker, ymd=None, get_days=14): - if ymd is None: - result = self.getCoinData(ticker, get_days=get_days) - else: - result = self.getCoinData(ticker, ymd=ymd, get_days=get_days) - - if len(result['ymd']) < 1: - return None, None - - #result_tic = self.makeTickData(result_m1, mins=minute) - data, current_index = self.analyze(result) - return data, current_index - -if __name__ == "__main__": - def min_max_normalize(data): - min_val = min(data) - max_val = max(data) - normalized_data = [(x - min_val) / (max_val - min_val) for x in data] - return normalized_data - - - # 예시 데이터 - original_data = [-4, -3, -2, -1, 0] - normalized_data = min_max_normalize(original_data) - print(np.asarray(normalized_data)-1) - original_data = [0, 2,4,6,8,10] - normalized_data = min_max_normalize(original_data) - print(normalized_data) \ No newline at end of file diff --git a/stock/analysis/JSDPattern_simulation.py b/stock/analysis/JSDPattern_simulation.py deleted file mode 100644 index 27e4f0f..0000000 --- a/stock/analysis/JSDPattern_simulation.py +++ /dev/null @@ -1,288 +0,0 @@ -# https://bibot.tistory.com/63 -# https://nonmeyet.tistory.com/entry/Python-TALib%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B9%84%ED%8A%B8%EC%BD%94%EC%9D%B8%EC%A3%BC%EA%B0%80%EA%B8%B0%EC%88%A0%EB%B6%84%EC%84%9D-%EB%B3%B4%EC%A1%B0%EC%A7%80%ED%91%9C-%EC%B6%94%EA%B0%80 -# https://lunadaddy.tistory.com/122 -# https://wikidocs.net/186885 - -import os -from scipy.signal import savgol_filter -import numpy as np -np.seterr(divide='ignore', invalid='ignore') -# https://www.lfd.uci.edu/~gohlke/pythonlibs/#ta-lib -# https://lunadaddy.tistory.com/122 -import talib -import pandas as pd -from datetime import datetime, timedelta - -from stock.analysis.IchimokuCloud import IchimokuCloud -from sklearn.preprocessing import StandardScaler -from stock.analysis.JSDPattern import JSDPattern - -class JSDPattern_simulation (JSDPattern): - - def __init__(self, RESOURCE_PATH=None): - super().__init__(RESOURCE_PATH) - return - - def analyze(self, result, mins=1440): - result["volume"] = [result["volume"][i] if 0 < result["volume"][i] else 1 for i in range(len(result["volume"]))] - # 기본 캔들 정보 - open_df = pd.DataFrame(result["open"]) - close_df = pd.DataFrame(result["close"]) - high_df = pd.DataFrame(result["high"]) - low_df = pd.DataFrame(result["low"]) - volume_df = pd.DataFrame(result["volume"]) - - # 중복 제거 - ymd_df = pd.DataFrame(result["ymd"]) - data_dup = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1) - data_dup.columns = ["ymd", "open", "close", "high", "low", "volume"] - data_dup.index = pd.DatetimeIndex(result["ymd"]) - data_dup_sorted = data_dup.sort_index(ascending=True) - data_dup_sorted = data_dup_sorted.drop_duplicates() - - ymd_df = data_dup_sorted["ymd"] - open_df = data_dup_sorted["open"] - close_df = data_dup_sorted["close"] - high_df = data_dup_sorted["high"] - low_df = data_dup_sorted["low"] - volume_df = data_dup_sorted["volume"] - - ymd = ymd_df.tolist() - open = open_df.tolist() - close = close_df.tolist() - high = high_df.tolist() - low = low_df.tolist() - volume = volume_df.tolist() - - # ichimokuCloud - df = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1) - column_names = ['DATE', 'open', 'close', 'high', 'low', 'volume'] - df.columns = column_names - c, b, l, s = 9, 26, 52, 26 - # 1. 전환선 = (과거 9일 동안 최고가 + 최저가) / 2 - # 당일을 포함한 9일 동안의 최고가와 최저가의 중간 값을 평균으로 나타낸다. - changeLine = (df.high.rolling(c).max() + df.low.rolling(c).min()) / 2 - # 2. 기준선 = 과거 26일 동안 최고가 + 최저가) / 2 - # 당일을 포함한 26일 동안의 최고가와 최저가의 중간 값을 평균으로 나타낸다. - baseLine = (df.high.rolling(b).max() + df.low.rolling(b).min()) / 2 - - # 3. 후행스팬 = 현재 close가격의 26일전 반영 - laggingSpan = [df.close.values[i + s] for i in range(len(df.close) - s)] - laggingSpan += [None for i in range(s)] - laggingSpan = np.array(laggingSpan) - - # 4. 선행스팬 1 = ((기준선 + 전환선) / 2)를 26일 선행하여 배치 - # 전환선과 기준선의 평균값을 구해 당일 포함 26일 앞으로 이동시킨 선 (중-단기 구간의 힘을 보여줌) - tmp_leadingSpan1 = (changeLine + baseLine) / 2 - """ S: 26일 선행시킴 """ - leadingSpan1 = list(tmp_leadingSpan1.values) - for i in range(b - 1): - leadingSpan1.insert(0, None) - """ E: 26일 선행시킴 """ - - # 5. 선행스팬 2 = ((최근 52일 동안 최고가 + 최저가) / 2)를 26일 선행하여 배치 - # 당일을 포함한 52일 동안의 최고가와 최저가의 평균을 26일 앞으로 이동시킨 선 (장기으로 형성된 선이기 때문에 가장 느리게 변함) - tmp_leadingSpan2 = (df.high.rolling(l).max() + df.low.rolling(l).min()) / 2 - """ S: 52일 선행시킴 """ - leadingSpan2 = list(tmp_leadingSpan2.values) - for i in range(l - 1): - leadingSpan2.insert(0, None) - """ S: 52일 선행시킴 """ - - baseLine = baseLine.tolist() - changeLine = changeLine.tolist() - laggingSpan = list(laggingSpan) - current_index = len(ymd) - for i in range(51): - if len(ymd) < len(leadingSpan2): - if mins==1440: - ymd.append(ymd[-1] + timedelta(days=1)) - else: - ymd.append(ymd[-1] + timedelta(minutes=1)) - if len(open) < len(leadingSpan2): - open.append(None) - if len(close) < len(leadingSpan2): - close.append(None) - if len(high) < len(leadingSpan2): - high.append(None) - if len(low) < len(leadingSpan2): - low.append(None) - if len(volume) < len(leadingSpan2): - volume.append(None) - if len(baseLine) < len(leadingSpan2): - baseLine.append(None) - if len(changeLine) < len(leadingSpan2): - changeLine.append(None) - if len(laggingSpan) < len(leadingSpan2): - laggingSpan.append(None) - for i in range(26): - if len(leadingSpan1) < len(leadingSpan2): - leadingSpan1.append(leadingSpan1[-1]) - - # 9일 신고가 - new_high_9 = [0 for c in range(8)] + [1 if (changeLine[c-1] is not None and changeLine[c] is not None and changeLine[c-1] < changeLine[c]) and None not in close[c-8:c+1] and max(close[c-8:c]) < close[c] else 0 for c in range(8, len(close))] - # 26일 신고가 - new_high_26 = [0 for c in range(25)] + [1 if (baseLine[c-1] is not None and baseLine[c] is not None and baseLine[c-1] < baseLine[c]) and None not in close[c-8:c+1] and max(close[c-25:c]) < close[c] else 0 for c in range(25, len(close))] - - # 9일 신저가 - new_low_9 = [0 for c in range(8)] + [1 if (changeLine[c-1] is not None and changeLine[c] is not None and changeLine[c-1] < changeLine[c]) and None not in close[c-8:c+1] and close[c-9] < min(close[c-8:c+1]) else 0 for c in range(8, len(close))] - # 26일 신저가 - new_low_26 = [0 for c in range(25)] + [1 if (baseLine[c-1] is not None and baseLine[c] is not None and baseLine[c-1] < baseLine[c]) and None not in close[c-8:c+1] and close[c-26] < min(close[c-25:c+1]) else 0 for c in range(25, len(close))] - - - # 이동 평균 - close_df = pd.DataFrame(close) - avg5 = list(np.reshape(close_df.ewm(5).mean().values, -1)) - avg10 = list(np.reshape(close_df.ewm(10).mean().values, -1)) - avg20 = list(np.reshape(close_df.ewm(20).mean().values, -1)) - avg60 = list(np.reshape(close_df.ewm(60).mean().values, -1)) - avg90 = list(np.reshape(close_df.ewm(90).mean().values, -1)) - avg120 = list(np.reshape(close_df.ewm(120).mean().values, -1)) - avg240 = list(np.reshape(close_df.ewm(240).mean().values, -1)) - avg360 = list(np.reshape(close_df.ewm(360).mean().values, -1)) - avg480 = list(np.reshape(close_df.ewm(480).mean().values, -1)) - avg720 = list(np.reshape(close_df.ewm(720).mean().values, -1)) - avg1440 = list(np.reshape(close_df.ewm(1440).mean().values, -1)) - avg2880 = list(np.reshape(close_df.ewm(2880).mean().values, -1)) - - np_high, np_low, np_close = np.array(high, dtype=np.float64), np.array(low, dtype=np.float64), np.array(close, dtype=np.float64) - slowk_12_df, slowd_12_df = talib.STOCH(np_high, np_low, np_close, fastk_period=12, slowk_period=5, slowk_matype=0, slowd_period=5, slowd_matype=0) - slowk_26_df, slowd_26_df = talib.STOCH(np_high, np_low, np_close, fastk_period=26, slowk_period=16, slowk_matype=0, slowd_period=16, slowd_matype=0) - slowk_52_df, slowd_52_df = talib.STOCH(np_high, np_low, np_close, fastk_period=52, slowk_period=32, slowk_matype=0, slowd_period=32, slowd_matype=0) - - - # 최고/최저 위치 - loc_240 = [None for i in range(len(close))] - for i in range(240, len(close)): - min_v = np.min(result["close"][i-239:i+1]) - max_v = np.max(result["close"][i-239:i+1]) - if close[i] is not None: - loc_240[i] = ((close[i] - min_v) / (max_v - min_v)) - else: - loc_240[i] = None - - loc_240 = pd.DataFrame(loc_240) - loc_240_k = loc_240.to_numpy().reshape(-1) - loc_240_d = loc_240.rolling(20).mean() - loc_240_s = loc_240.rolling(60).mean() - loc_240_d = loc_240_d.to_numpy().reshape(-1) - loc_240_s = loc_240_s.to_numpy().reshape(-1) - - # 볼린저 밴드 - n, t = 10, 2 - max_10 = close_df.rolling(window=n).mean() - stddev_10 = close_df.rolling(window=n).std() - upper_10 = max_10 + (stddev_10 * t) # 상단 볼리저 밴드 - lower_10 = max_10 - (stddev_10 * t) # 하단 볼리저 밴드 - middle_10 = (upper_10 + lower_10) / 2 - upper_10 = list(np.reshape(upper_10.values, -1)) - lower_10 = list(np.reshape(lower_10.values, -1)) - middle_10 = list(np.reshape(middle_10.values, -1)) - - n, t = 20, 2 - max_20 = close_df.rolling(window=n).mean() - stddev_20 = close_df.rolling(window=n).std() - upper_20 = max_20 + (stddev_20 * t) # 상단 볼리저 밴드 - lower_20 = max_20 - (stddev_20 * t) # 하단 볼리저 밴드 - middle_20 = (upper_20 + lower_20) / 2 - upper_20 = list(np.reshape(upper_20.values, -1)) - lower_20 = list(np.reshape(lower_20.values, -1)) - middle_20 = list(np.reshape(middle_20.values, -1)) - - duration = 1440 - if mins == 1440: - duration = 360 - laggingSpan_close_diff, laggingSpan_close_diff_rate = self.getDiff_Rate(laggingSpan, close, duration=duration) - laggingSpan_avg60_diff, laggingSpan_avg60_diff_rate = self.getDiff_Rate(laggingSpan, avg60, duration=duration) - leadingSpan1_leadingSpan2_diff, leadingSpan1_leadingSpan2_diff_rate = self.getDiff_Rate(leadingSpan1, leadingSpan2, duration=duration) - - - df_list = [ - pd.DataFrame(ymd), - pd.DataFrame(open), pd.DataFrame(close), pd.DataFrame(high), pd.DataFrame(low), pd.DataFrame(volume), - pd.DataFrame(changeLine), pd.DataFrame(baseLine), pd.DataFrame(laggingSpan), pd.DataFrame(leadingSpan1), pd.DataFrame(leadingSpan2), - - pd.DataFrame(laggingSpan_close_diff), - pd.DataFrame(laggingSpan_avg60_diff), - pd.DataFrame(leadingSpan1_leadingSpan2_diff), - - pd.DataFrame(laggingSpan_close_diff_rate), - pd.DataFrame(laggingSpan_avg60_diff_rate), - pd.DataFrame(leadingSpan1_leadingSpan2_diff_rate), - - pd.DataFrame(loc_240_k), pd.DataFrame(loc_240_d), pd.DataFrame(loc_240_s), - - pd.DataFrame(avg5), pd.DataFrame(avg10), pd.DataFrame(avg20), pd.DataFrame(avg60), pd.DataFrame(avg90), pd.DataFrame(avg120), pd.DataFrame(avg240), pd.DataFrame(avg360), pd.DataFrame(avg480), pd.DataFrame(avg720), pd.DataFrame(avg1440), pd.DataFrame(avg2880), - pd.DataFrame(upper_10), pd.DataFrame(lower_10), pd.DataFrame(middle_10), - pd.DataFrame(upper_20), pd.DataFrame(lower_20), pd.DataFrame(middle_20), - - pd.DataFrame(new_high_9), pd.DataFrame(new_high_26), - pd.DataFrame(new_low_9), pd.DataFrame(new_low_26), - pd.DataFrame(slowk_12_df), pd.DataFrame(slowd_12_df), - pd.DataFrame(slowk_26_df), pd.DataFrame(slowd_26_df), - pd.DataFrame(slowk_52_df), pd.DataFrame(slowd_52_df), - - ] - - data = pd.concat(df_list, axis=1) - column_names = [ - 'ymd', - 'open', 'close', 'high', 'low', 'volume', - 'changeLine', 'baseLine', 'laggingSpan', 'leadingSpan1', 'leadingSpan2', - - 'laggingSpan_close_diff', - 'laggingSpan_avg60_diff', - 'leadingSpan1_leadingSpan2_diff', - - 'laggingSpan_close_diff_rate', - 'laggingSpan_avg60_diff_rate', - 'leadingSpan1_leadingSpan2_diff_rate', - - 'loc_240_k', 'loc_240_d', 'loc_240_s', - - 'avg5', 'avg10', 'avg20', 'avg60', 'avg90', 'avg120', 'avg240', 'avg360', 'avg480', 'avg720', 'avg1440', 'avg2880', - - 'upper_10', 'lower_10', 'middle_10', - 'upper_20', 'lower_20', 'middle_20', - - 'new_high_9', 'new_high_26', - 'new_low_9', 'new_low_26', - - 'slowk_12', 'slowd_12', - 'slowk_26', 'slowd_26', - 'slowk_52', 'slowd_52', - ] - data.columns = column_names - data.index = pd.DatetimeIndex(ymd) - - return data, current_index - - def getData(self, ticker, ymd=None, get_days=14): - if ymd is None: - result = self.getCoinData(ticker, get_days=get_days) - else: - result = self.getCoinData(ticker, ymd=ymd, get_days=get_days) - - if len(result['ymd']) < 1: - return None, None - - #result_tic = self.makeTickData(result_m1, mins=minute) - data, current_index = self.analyze(result) - return data, current_index - - -if __name__ == "__main__": - def min_max_normalize(data): - min_val = min(data) - max_val = max(data) - normalized_data = [(x - min_val) / (max_val - min_val) for x in data] - return normalized_data - - - # 예시 데이터 - original_data = [-4, -3, -2, -1, 0] - normalized_data = min_max_normalize(original_data) - print(np.asarray(normalized_data)-1) - original_data = [0, 2,4,6,8,10] - normalized_data = min_max_normalize(original_data) - print(normalized_data) \ No newline at end of file diff --git a/stock/crawler/FnGuideCrawler.py b/stock/crawler/FnGuideCrawler.py index b8b08c4..6da1994 100644 --- a/stock/crawler/FnGuideCrawler.py +++ b/stock/crawler/FnGuideCrawler.py @@ -121,7 +121,7 @@ class FnGuideCrawler: item_code = item[1] idx += 1 - print(idx, item_code, item_name, 'http://comp.fnguide.com/SVO2/ASP/SVD_main.asp?pGB=1&gicode=A%s'%(item_code.strip())) + print("{}. {} ({}) {}".format(idx, item_code, item_name, 'http://comp.fnguide.com/SVO2/ASP/SVD_main.asp?pGB=1&gicode=A%s'%(item_code.strip()))) fnGuideData = self.get_fnguide_table(item_code) diff --git a/stock/crawler/MetaCrawler.py b/stock/crawler/MetaCrawler.py index 0c61b89..f765928 100644 --- a/stock/crawler/MetaCrawler.py +++ b/stock/crawler/MetaCrawler.py @@ -46,8 +46,8 @@ class MetaCrawler: inputs.append({'NAME': 'RUB', 'CODE': 'FX_RUBKRW', 'URL': 'http://finance.naver.com/marketindex/exchangeDailyQuote.nhn?marketindexCd=FX_RUBKRW'}) # 러시아 RUB inputs.append({'NAME': 'TWD', 'CODE': 'FX_TWDKRW', 'URL': 'http://finance.naver.com/marketindex/exchangeDailyQuote.nhn?marketindexCd=FX_TWDKRW'}) # 대만 TWD - for i in range(len(inputs)): - input = inputs[i] + for idx in range(len(inputs)): + input = inputs[idx] NAME = input['NAME'] CODE = input['CODE'] @@ -100,7 +100,7 @@ class MetaCrawler: finish = True break - print(CODE, NAME, ymd) + print("{}. {} {} ({})".format(idx, ymd, CODE, NAME)) if finish: break @@ -191,7 +191,7 @@ class MetaCrawler: finish = True break - print ("20"+item[0]) + print ("Trading_Trend 20{}".format(item[0])) previousDay = html[0].values[2][0] if finish: break @@ -271,7 +271,7 @@ class MetaCrawler: finish = True break - print("20"+item[0]) + print("crawl_money_trend 20{}".format(item[0])) if finish: break previousDay = html[0].values[2][0] @@ -301,8 +301,8 @@ class MetaCrawler: inputs.append({'NAME': '국고채(3년)', 'CODE': 'IRR_GOVT03Y', 'URL': 'http://finance.naver.com/marketindex/interestDailyQuote.nhn?marketindexCd=IRR_GOVT03Y'}) inputs.append({'NAME': '회사채(3년)', 'CODE': 'IRR_CORP03Y', 'URL': 'http://finance.naver.com/marketindex/interestDailyQuote.nhn?marketindexCd=IRR_CORP03Y'}) - for i in range(len(inputs)): - input = inputs[i] + for idx in range(len(inputs)): + input = inputs[idx] NAME = input['NAME'] CODE = input['CODE'] @@ -357,7 +357,7 @@ class MetaCrawler: if finish: break - print(NAME + " / " + ymd) + print("{} {}".format(ymd, NAME)) conn.commit() cursor.close() @@ -393,8 +393,8 @@ class MetaCrawler: inputs.append({'NAME': 'PLATINUM', 'CODE': 'CMDT_PL','URL': 'http://finance.naver.com/marketindex/worldDailyQuote.nhn?marketindexCd=CMDT_PL&fdtc=2'}) # 국제 백금 inputs.append({'NAME': 'PALADIUM', 'CODE': 'CMDT_PA','URL': 'http://finance.naver.com/marketindex/worldDailyQuote.nhn?marketindexCd=CMDT_PA&fdtc=2'}) # 국제 팔라듐 - for i in range(len(inputs)): - input = inputs[i] + for idx in range(len(inputs)): + input = inputs[idx] NAME = input['NAME'] CODE = input['CODE'] @@ -444,7 +444,7 @@ class MetaCrawler: finish = True break - print(CODE, NAME, ymd) + print("{}. {} {} ({})".format(idx, ymd, CODE, NAME)) if finish: break diff --git a/stock/crawler/StockCrawler.py b/stock/crawler/StockCrawler.py index b098aca..3c8648c 100644 --- a/stock/crawler/StockCrawler.py +++ b/stock/crawler/StockCrawler.py @@ -132,10 +132,7 @@ class StockCrawler: stocks.append({"NAME": 'KODEX 은행', "CODE": "091170"}) stocks.append({"NAME": 'TIGER 탄소효율그린뉴딜', "CODE": "376410"}) - start_time = time.time() for i, stock in enumerate(stocks): - print (i, stock["NAME"], stock["CODE"], (time.time()-start_time), "s") - start_time = time.time() cursor.execute('SELECT ymd FROM ' + tableName + ' WHERE CODE=? order by ymd desc', (stock["CODE"],)) result = cursor.fetchone() ymd = self.START_DATE @@ -153,6 +150,7 @@ class StockCrawler: #else: # cursor.execute("UPDATE " + tableName + " SET close=?, diff=?, open=?, high=?, low=?, volume=? WHERE CODE=? and ymd=?", (item['close'], item['diff'], item['open'], item['high'], item['low'], item['volume'], stock["CODE"], item['ymd'])) + print("{}. {} ({})".format(i, stock["CODE"], stock["NAME"])) sleep(0.5) conn.commit() cursor.close() @@ -178,7 +176,6 @@ class StockCrawler: code_df = self.getStockInfo() items = code_df.values - start_time = time.time() idx = 0 for item in items: idx += 1 @@ -211,9 +208,7 @@ class StockCrawler: conn.commit() cursor.close() conn.close() - print(idx, item_name, item_code, (time.time() - start_time), "s") - - start_time = time.time() + print("{}. {} ({})".format(idx, item_code, item_name)) sleep(0.3) return @@ -234,8 +229,6 @@ class StockCrawler: cursor.close() conn.close() - start_time = time.time() - pd.options.display.float_format = '{:.4f}'.format pd.set_option('display.max_columns', None) @@ -372,9 +365,8 @@ class StockCrawler: conn.commit() cursor.close() conn.close() - print(idx, item_code, special_stocks[item_code], (time.time() - start_time), "s") - start_time = time.time() + print("{}. {} ({})".format(idx, item_code, special_stocks[item_code])) sleep(0.05) return