From c6a1698f33c78eee5bd1bdfb528cddff71e4a006 Mon Sep 17 00:00:00 2001 From: dsyoon Date: Sun, 29 Jan 2023 22:00:36 +0900 Subject: [PATCH] init --- HTS_122630.py | 191 ------------------------------------ HTS_252670.py => HTS_etf.py | 126 ++++++++++++------------ hts/BuySellChecker.py | 2 +- hts/HTS.py | 42 ++++---- 4 files changed, 87 insertions(+), 274 deletions(-) delete mode 100644 HTS_122630.py rename HTS_252670.py => HTS_etf.py (55%) diff --git a/HTS_122630.py b/HTS_122630.py deleted file mode 100644 index 2a07f51..0000000 --- a/HTS_122630.py +++ /dev/null @@ -1,191 +0,0 @@ -import time -import os -from datetime import datetime, timedelta -import pandas as pd - -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 - -class HTS_122630 (HTS): - RESOURCE_PATH = None - stock_code = None - buy_count = None - orderChecker = None - buySellChecker = None - labelChecker = None - - def __init__(self, RESOURCE_PATH, stock_code, buy_count): - super().__init__(RESOURCE_PATH) - - self.RESOURCE_PATH = RESOURCE_PATH - self.stock_code = stock_code - self.buy_count = buy_count - - self.orderChecker = OrderChecker(self.RESOURCE_PATH, self.stock_code) - self.buySellChecker = BuySellChecker() - self.labelChecker = LabelChecker(RESOURCE_PATH) - return - - def getSellingPrice(self, log_time, stock_code, final_price, check=False): - # final_price와 diff를 받으면, 해당 가격으로 그냥 매도한다는 의미 - # final_price와 diff가 None이면 장부가와 final 중 max로 팔겠다는 의미 - # final_price가 0이고 diff가 None이면 장부가로 팔겠다는 의미임 - jangoDic = self.requstJango() - if jangoDic and len(jangoDic.keys()) > 0: - for code in jangoDic: - if jangoDic[code]['매도가능'] > 0: - if check: - if jangoDic[code]['장부가'] * 0.05 < jangoDic[code]['장부가'] - final_price: - sell_price = jangoDic[code]['장부가'] - if code == "A" + stock_code: - orderNum = self.requestOrder(OrderType.sell, stock_code, jangoDic[code]['매도가능'], sell_price) - print("ORDER_SELL", stock_code, 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) - print("ORDER_SELL", stock_code, log_time.strftime('%Y%m%d %H%M%S'), jangoDic[code]['매도가능'], sell_price) - return - - def buyRealTime(self, today): - - print ("START...") - THIS_TIME = datetime.now() - final_sell_check = False - LAST_DATA = self.getLastData(self.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'): - # 3시 까지만 매수를 시도한다. - - if THIS_TIME < datetime.strptime(today + " 145000", '%Y%m%d %H%M%S'): - if THIS_TIME.strftime('%S') in ("09", "19", "29", "39", "49", "59"): - # 데이터를 가지고 온다. - result = self.getRealTime(self.stock_code, today, LAST_DATA) - final_price = result["close"][len(result["close"])-1] - - # 10초마다 체크하여 체결된 내역이 있으면 50원 높게 매도를 주문한다. - self.getSellingPrice(THIS_TIME, self.stock_code, final_price, check=True) - - if THIS_TIME.strftime('%S') == "05": - # 매분 5초마다 실행한다. - - # 데이터를 가지고 온다. - result = self.getRealTime(self.stock_code, today, LAST_DATA) - - # 규칙 기반의 분석을 통해서 볼린저밴드 상/하단을 계산한다. - data = self.buySellChecker.analyze(result) - - # 만약 미체결 내역이 있는데, 지표가 꺽여 내려온다면, 매수 주문을 취소 시킨다. - last_index = len(data['close']) - 1 - if data['slow_k'][last_index - 1] >= 80 and data['slow_k'][last_index - 1] > data['slow_k'][ - last_index]: - # 미체결 기록을 가져온다. - ORDER_LIST = self.requestOrderList() - orderListToCancel = self.orderChecker.remove(self.stock_code, OrderType.sell, ORDER_LIST) - self.cancelOrderList(orderListToCancel) - print("CANCEL", THIS_TIME.strftime('%Y%m%d %H%M%S'), len(orderListToCancel), len(ORDER_LIST)) - - - # 사야 할 시점/가격과 팔아야 할 시점/가격을 체크한다. - bsLine, data = self.buySellChecker.checkTransaction(data, self.stock_code, isRealTime=True) - bs_buy_price = bsLine['buy'][0] - bs_buy_weight = bsLine['buy_weight'][0] - bs_sell_price = bsLine['sell'][0] - - data_size = len(data["close"]) - final_price = data["close"][data_size-1] - - if bs_buy_price > 0: - # 기본 100 주에 가중치를 추가해서 매수한다. - BUY_COUNT = int(self.buy_count * bs_buy_weight) - - # 매수를 주문한다. - orderNum = self.requestOrder(OrderType.buy, self.stock_code, BUY_COUNT, bs_buy_price) - - # 미체결 기록을 가져온다. - ORDER_LIST = self.requestOrderList() - # 매수 주문을 기록한다. - orderListToCancel = self.orderChecker.add(self.stock_code, OrderType.buy, orderNum, BUY_COUNT, bs_buy_price, ORDER_LIST) - # 두 시간 이전 미체결을 모두 취소한다. - self.cancelOrderList(orderListToCancel) - # 로그 출력 - print("BUY", THIS_TIME.strftime('%Y%m%d %H%M%S'), BUY_COUNT, bs_buy_price, len(orderListToCancel), len(ORDER_LIST)) - - - if bs_sell_price > 0: - # 미체결 기록을 가져온다. - ORDER_LIST = self.requestOrderList() - # 매도 주문을 기록을 가져온다. - orderListToCancel = self.orderChecker.remove(self.stock_code, OrderType.sell, ORDER_LIST) - # 매도 미체결을 모두 취소한다. - self.cancelOrderList(orderListToCancel) - - # 매도 한다. - self.getSellingPrice(THIS_TIME, self.stock_code, final_price) - - - # 로그 출력 - print("TIMECHECK: %s, price: %d, avg3: %.2f, avg5: %.2f, avg10: %.2f, slow_k: %.2f, open: %d, high: %d, low: %d" % - (str(THIS_TIME), final_price, - data["avg3"][data_size - 1], data["avg6"][data_size - 1], data["avg9"][data_size - 1], data["slow_k"][data_size - 2], - data["open"][data_size - 1], data["high"][data_size - 1], data["low"][data_size - 1],)) - - 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: - #### - # 손해봐도 매도한다. - #### - - # 주문 리스트를 가져온다. - orderList = self.requestOrderList() - # 15:10:00 이후라면 모든 미체결 취소한다. - self.cancelOrderList(orderList) - - # 매도 가격을 가져온다. - result = self.getRealTime(self.stock_code, today, LAST_DATA) - final_price = result["close"][len(result["close"]) - 1] - - self.getSellingPrice(THIS_TIME, self.stock_code, final_price) - - final_sell_check = True - - time.sleep(10) - THIS_TIME = datetime.now() - 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 - -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 레버리지" - buy_count = 50 - - hts = HTS_122630(RESOURCE_PATH, stock_code, buy_count) - today_str = today.strftime('%Y%m%d') - today_str = "20220916" - hts.buyRealTime(today_str) - - db_filename = os.path.join(RESOURCE_PATH, "hts.db") - hts.insertStockData(db_filename, stock_code, stock_name, today_str) - #hts.updteTodayStock(db_filename, stock_code, today_str) - - print ("done...") diff --git a/HTS_252670.py b/HTS_etf.py similarity index 55% rename from HTS_252670.py rename to HTS_etf.py index 65b10ff..10713e1 100644 --- a/HTS_252670.py +++ b/HTS_etf.py @@ -11,7 +11,7 @@ from stock.util.LabelChecker import LabelChecker from stock.util.SlackBot import SlackBot from stock.analysis.StockStatus import StockStatus -class HTS_252670 (HTS): +class HTS_etf (HTS): RESOURCE_PATH = None stock_code = None @@ -21,13 +21,12 @@ class HTS_252670 (HTS): labelChecker = None slackBot = None stockStatus = None + MAX_BUY_PRICE = None - def __init__(self, RESOURCE_PATH, stock_code, buy_count): + def __init__(self, RESOURCE_PATH): super().__init__(RESOURCE_PATH) self.RESOURCE_PATH = RESOURCE_PATH - self.stock_code = stock_code - self.buy_count = buy_count self.orderChecker = OrderChecker(self.RESOURCE_PATH) self.buySellChecker = BuySellChecker() @@ -35,9 +34,11 @@ class HTS_252670 (HTS): self.slackBot = SlackBot() self.stockStatus = StockStatus(RESOURCE_PATH) + self.MAX_BUY_PRICE = 500000 + return - def getSellingPrice(self, log_time, stock_code, final_price, check=False): + 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이면 장부가로 팔겠다는 의미임 @@ -47,7 +48,7 @@ class HTS_252670 (HTS): if jangoDic and len(jangoDic.keys()) > 0: for code in jangoDic: if jangoDic[code]['매도가능'] > 0: - if check: + if without_loss: if jangoDic[code]['장부가']*0.05 < jangoDic[code]['장부가'] - final_price: sell_price = jangoDic[code]['장부가'] if code == "A" + stock_code: @@ -83,12 +84,15 @@ class HTS_252670 (HTS): return result - def buyRealTime(self, today, analyzed_day=1000): + def buyRealTime(self, today, stocks, analyzed_day=1000): print ("START...") THIS_TIME = datetime.now() final_sell_check = False - LAST_DATA = self.getLastData(self.stock_code, today) + + 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'): @@ -98,62 +102,61 @@ class HTS_252670 (HTS): if THIS_TIME.strftime('%S') == "03": # 매분 3초마다 실행한다. - # 데이터를 가지고 온다. - result = self.getRealTime(self.stock_code, today, LAST_DATA) + for stock in stocks: - result_5 = self.makeTickData(result, mins=5) - result_30 = self.makeTickData(result, mins=30) + # 데이터를 가지고 온다. + result = self.getRealTime(stock['stock_code'], today, LAST_DATA[stock['stock_code']]) - data = self.buySellChecker.analyze(result) - data.drop(data.index[:len(data) - analyzed_day], inplace=True) + result_5 = self.makeTickData(result, mins=5) + result_30 = self.makeTickData(result, mins=30) - # 이동평균, RSI, MACD, 일목균형, 볼린저밴드 상/하단을 계산한다. - data_5 = self.buySellChecker.analyze(result_5) - # 분석일 데이터만 활용한다 (이전 데이터는 제거) - data_5.drop(data_5.index[:len(data_5) - analyzed_day], inplace=True) + data = self.buySellChecker.analyze(result) + data.drop(data.index[:len(data) - analyzed_day], inplace=True) - data_30 = self.buySellChecker.analyze(result_30) - # 분석일 데이터만 활용한다 (이전 데이터는 제거) - data_30.drop(data_30.index[:len(data_30) - analyzed_day], inplace=True) + # 5분 이동평균, RSI, MACD, 일목균형, 볼린저밴드 상/하단을 계산한다. + data_5 = self.buySellChecker.analyze(result_5) + # 분석일 데이터만 활용한다 (이전 데이터는 제거) + data_5.drop(data_5.index[:len(data_5) - analyzed_day], inplace=True) - # 사야 할 시점과 팔아야 할 시점을 체크한다. - bsLine = self.buySellChecker.checkTransaction(stock_code, data, data_5, data_30, isRealTime=True) - bs_buy_price = bsLine['buy'][0] - bs_buy_weight = bsLine['buy_weight'][0] - bs_sell_price = bsLine['sell'][0] + # 30분 이동평균, RSI, MACD, 일목균형, 볼린저밴드 상/하단을 계산한다. + data_30 = self.buySellChecker.analyze(result_30) + # 분석일 데이터만 활용한다 (이전 데이터는 제거) + data_30.drop(data_30.index[:len(data_30) - analyzed_day], inplace=True) - data_size = len(data["close"]) - final_price = data["close"][data_size-1] + # 사야 할 시점과 팔아야 할 시점을 체크한다. + bsLine = self.buySellChecker.checkTransaction(data, data_5, data_30, isRealTime=True) + bs_buy_price = bsLine['buy'][0] + bs_buy_weight = bsLine['buy_weight'][0] + bs_sell_price = bsLine['sell'][0] - if bs_buy_price > 0: - # 기본 100 주에 가중치를 추가해서 매수한다. - BUY_COUNT = int(self.buy_count * bs_buy_weight) + if bs_buy_price > 0: + buy_count = int(self.MAX_BUY_PRICE/bs_buy_price) - # 매수를 주문한다. - orderNum = self.requestOrder(OrderType.buy, self.stock_code, BUY_COUNT , bs_buy_price) - # slackbot에 메시지를 보냄 - self.slackBot.post_to_slack(stock_code, stock_name, "BUY", bsLine['buy'][len(bsLine['buy']) - 1], buy_count) - self.orderChecker.add(today, stock_code, 1, buy_count, bs_buy_price, orderNum) + # 매수를 주문한다. + orderNum = self.requestOrder(OrderType.buy, self.stock_code, buy_count , bs_buy_price) + # slackbot에 메시지를 보냄 + self.slackBot.post_to_slack(stock['stock_code'], stock['stock_name'], "BUY", bsLine['buy'][len(bsLine['buy']) - 1], buy_count) + self.orderChecker.add(today, stock['stock_code'], 1, buy_count, bs_buy_price, orderNum) + + # 로그 출력 + print("BUY", THIS_TIME.strftime('%Y%m%d %H%M%S'), orderNum, stock['stock_code'], stock['stock_name'], bs_buy_price, buy_count) + + + if bs_sell_price > 0: + # 매도한다. + orderNum = self.getSellingPrice(THIS_TIME, self.stock_code, bs_sell_price, without_loss=True) + + # slackbot에 메시지를 보냄 + self.slackBot.post_to_slack(stock['stock_code'], stock['stock_name'], "SELL", bsLine['sell'][len(bsLine['sell']) - 1], -1) + self.orderChecker.delete(today, stock['stock_code']) + + # 로그 출력 + print("SELL", THIS_TIME.strftime('%Y%m%d %H%M%S'), str(orderNum), stock['stock_code'], stock['stock_name'], bs_sell_price) # 로그 출력 - print("BUY", THIS_TIME.strftime('%Y%m%d %H%M%S'), orderNum, stock_code, stock_name, bs_buy_price, buy_count) - - - if bs_sell_price > 0: - # 매도한다. - orderNum = self.getSellingPrice(THIS_TIME, self.stock_code, final_price) - - # slackbot에 메시지를 보냄 - self.slackBot.post_to_slack(stock_code, stock_name, "SELL", bsLine['sell'][len(bsLine['sell']) - 1], -1) - self.orderChecker.delete(today, stock_code) - - # 로그 출력 - print("SELL", THIS_TIME.strftime('%Y%m%d %H%M%S'), str(orderNum), stock_code, stock_name, bs_sell_price) - - # 로그 출력 - print("TIMECHECK: %s, price: %d, avg5: %.2f, avg30: %.2f, slow_k: %.2f, open: %d, high: %d, low: %d" % - (str(THIS_TIME), final_price, data["avg5"][data_size - 1], data["avg30"][data_size - 1], - data["slow_k"][data_size - 2], data["open"][data_size - 1], data["high"][data_size - 1], data["low"][data_size - 1],)) + print("TIMECHECK: %s, code: %s, name: %s, buy: %d, sell: %d, avg5: %.2f, avg30: %.2f, open: %d, high: %d, low: %d, slow_k: %.2f, slow_k_5: %.2f, slow_k_30: %.2f" % + (str(THIS_TIME), stock['stock_code'], stock['stock_name'], bs_buy_price, bs_sell_price, data["avg5"][0], data["avg30"][0], + data["open"][0], data["high"][0], data["low"][0], data["slow_k"][0], data_5["slow_k"][0], data_30["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분 사이는 잔량을 매도한다. @@ -195,17 +198,16 @@ if __name__ == "__main__": RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources") # KODEX 인버스 * 2 - stock_code = "252670" - stock_name = "KODEX 200선물인버스2X" - buy_count = 2000 + stocks = [ + {"stock_code": "252670", "stock_name": "KODEX 200선물인버스2X"}, + {"stock_code": "122630", "stock_name": "KODEX 레버리지"} + ] - hts = HTS_252670(RESOURCE_PATH, stock_code, buy_count) + hts = HTS_etf(RESOURCE_PATH) today_str = today.strftime('%Y%m%d') - #today_str = "20220916" - hts.buyRealTime(today_str) + hts.buyRealTime(today_str, stocks, analyzed_day=1000) db_filename = os.path.join(RESOURCE_PATH, "hts.db") - hts.insertStockData(db_filename, stock_code, stock_name, today_str) - #hts.updteTodayStock(db_filename, stock_code, today_str) + hts.insertStockData(db_filename, today_str, stocks) print ("done...") diff --git a/hts/BuySellChecker.py b/hts/BuySellChecker.py index e7952de..7b29f08 100644 --- a/hts/BuySellChecker.py +++ b/hts/BuySellChecker.py @@ -720,7 +720,7 @@ class BuySellChecker: outFp.write(str(df["label"][i]) + "\n") return - def checkTransaction(self, stock_code, data, data_5, data_30, isRealTime=True): + def checkTransaction(self, data, data_5, data_30, isRealTime=True): # 어제 오늘 데이터로 분석 bsLine = {} size = len(data["close"]) diff --git a/hts/HTS.py b/hts/HTS.py index 490b592..ab017d5 100644 --- a/hts/HTS.py +++ b/hts/HTS.py @@ -456,7 +456,7 @@ class HTS: return data - def insertStockData(self, db_filename, stock_code, stock_name, today): + def insertStockData(self, db_filename, today, stocks): tableName = 'hts' conn = sqlite3.connect(db_filename) cursor = conn.cursor() @@ -472,29 +472,31 @@ class HTS: cursor.close() conn.close() - items = self.getStockInfo(stock_code, today) + for stock in stocks: + items = self.getStockInfo(stock["stock_code"], today) - conn = sqlite3.connect(db_filename) - cursor = conn.cursor() - idx = 0 - for item in items: - ymd = item[0] - hms = item[1] - open = item[2] - high = item[3] - low = item[4] - close = item[5] - volume = item[6] + conn = sqlite3.connect(db_filename) + cursor = conn.cursor() + idx = 0 + for item in items: + ymd = item[0] + hms = item[1] + open = item[2] + high = item[3] + low = item[4] + close = item[5] + volume = item[6] - idx += 1 + idx += 1 - cursor.execute('DELETE FROM ' + tableName + ' WHERE CODE=? and ymd=? and hms=?', (stock_code, ymd, hms,)) - cursor.execute("INSERT INTO " + tableName + "(CODE, NAME, ymd, hms, close, open, high, low, volume) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)", (stock_code, stock_name, ymd, hms, close, open, high, low, volume)) + cursor.execute('DELETE FROM ' + tableName + ' WHERE CODE=? and ymd=? and hms=?', (stock["stock_code"], ymd, hms,)) + cursor.execute("INSERT INTO " + tableName + "(CODE, NAME, ymd, hms, close, open, high, low, volume) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)", (stock["stock_code"], stock["stock_name"], ymd, hms, close, open, high, low, volume)) - conn.commit() - cursor.close() - conn.close() - print("insert...", stock_code, stock_name, today) + conn.commit() + cursor.close() + conn.close() + + print("insert...", stock["stock_code"], stock["stock_name"], today) return