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