diff --git a/HTS_252670_daily.py b/HTS_252670_daily.py deleted file mode 100644 index a85e4cf..0000000 --- a/HTS_252670_daily.py +++ /dev/null @@ -1,185 +0,0 @@ -import time -import os -from datetime import datetime - -from stock.analysis.DailyStatus import DailyStatus -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_252670_DAILY (HTS): - - RESOURCE_PATH = None - stock_code = None - buy_count = None - orderChecker = None - buySellChecker = None - labelChecker = None - dailyStatus = 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) - self.dailyStatus = DailyStatus(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이면 장부가로 팔겠다는 의미임 - - sell_price = -1 - 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.dailyStatus.getLastData(stock_code, 200) - - while datetime.strptime(today + " 070000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 153100", '%Y%m%d %H%M%S'): - - # 1515 까지만 매수를 시도한다. - 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.strftime('%S') == "03": - - # 데이터를 가지고 온다. - 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) - # 1 시간 이전 미체결을 모두 취소한다. - 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(0.9) - 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 = "252670" - stock_name = "KODEX 200선물인버스2X" - buy_count = 900 - - hts = HTS_252670_DAILY(RESOURCE_PATH, stock_code, buy_count) - today_str = today.strftime('%Y%m%d') - hts.buyRealTime(today_str) - - db_filename = os.path.join(RESOURCE_PATH, "hts.db") - #today_str = "20220916" - hts.insertStockData(db_filename, stock_code, stock_name, today_str) - #hts.updteTodayStock(db_filename, stock_code, today_str) - - print ("done...") diff --git a/HTS_daily.py b/HTS_daily.py new file mode 100644 index 0000000..d791181 --- /dev/null +++ b/HTS_daily.py @@ -0,0 +1,133 @@ +import time +import os +import sqlite3 +from datetime import datetime + +from stock.analysis.DailyStatus import DailyStatus +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_DAILY (HTS): + + RESOURCE_PATH = None + stock_code = None + buy_count = None + orderChecker = None + buySellChecker = None + labelChecker = None + dailyStatus = None + analyzed_day = None + MAX_BUY_PRICE = None + + def __init__(self, RESOURCE_PATH): + super().__init__(RESOURCE_PATH) + + self.RESOURCE_PATH = RESOURCE_PATH + self.dailyStatus = DailyStatus(RESOURCE_PATH) + self.analyzed_day = 60 + self.MAX_BUY_PRICE = 500000 + 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이면 장부가로 팔겠다는 의미임 + + sell_price = -1 + 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, 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'): + + # 1515 까지만 매수를 시도한다. + if datetime.strptime(today + " 090000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 151500", '%Y%m%d %H%M%S'): + + stockTableName = 'stock' + conn = sqlite3.connect(os.path.join(self.RESOURCE_PATH, self.dbFileName)) + cursor = conn.cursor() + cursor.execute('SELECT distinct code, name FROM ' + stockTableName + ' order by code') + items = cursor.fetchall() + cursor.close() + conn.close() + + for idx, item in enumerate(items): + stock_code = item[0] + stock_name = item[1] + if stock_name.find('스팩') >= 0: + continue + print(idx, stock_code, stock_name) + print("Analysis # :", idx, ", CODE: ", stock_code, ", NAME: ", stock_name) + + stock = self.dailyStatus.getLastData(stock_code, n) + self.getRealTime_DailyCheck(today, stock_code, stock) + + data = self.dailyStatus.analyze(stock, self.analyzed_day) + # 분석일 데이터만 활용한다 (이전 데이터는 제거) + data.drop(data.index[:self.analyzed_day], inplace=True) + + bsLine, data = self.buySellChecker.checkTransactionWithEnvelope(data, stock_code, isRealTime=False) + + if len(data.index) > 10 and max(bsLine['buy'][len(bsLine['buy']) - 2:]) > 0: + last_index = len(bsLine['buy'])-1 + if bsLine['buy'][last_index] > 0: + bs_buy_price = bsLine['buy'][last_index] + bs_buy_weight = bsLine['buy_weight'][last_index] + buy_count = int(self.MAX_BUY_PRICE / bs_buy_price) + + # 매수를 주문한다. + orderNum = self.requestOrder(OrderType.buy, stock_code, buy_count, bs_buy_price) + + # 로그 출력 + print("BUY", THIS_TIME.strftime('%Y%m%d %H%M%S'), orderNum, stock_code, stock_name, bs_buy_price, buy_count) + + 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") + + hts = HTS_DAILY(RESOURCE_PATH) + today_str = today.strftime('%Y%m%d') + hts.buyRealTime(today_str) + + db_filename = os.path.join(RESOURCE_PATH, "hts.db") + #today_str = "20220916" + hts.insertStockData(db_filename, stock_code, stock_name, today_str) + #hts.updteTodayStock(db_filename, stock_code, today_str) + + print ("done...") diff --git a/hts/HTS.py b/hts/HTS.py index ab16816..490b592 100644 --- a/hts/HTS.py +++ b/hts/HTS.py @@ -749,6 +749,105 @@ class HTS: return result + def getRealTime_DailyCheck(self, today, stock_code, stock): + objCpCybos = win32com.client.Dispatch("CpUtil.CpCybos") + bConnect = objCpCybos.IsConnect + if (bConnect == 0): + print("PLUS가 정상적으로 연결되지 않음. ") + exit() + + # 차트 객체 구하기 + objStockChart = win32com.client.Dispatch("CpSysDib.StockChart") + + objStockChart.SetInputValue(0, 'A'+stock_code) # 종목 코드 + objStockChart.SetInputValue(1, ord('1')) # 1: 기간으로 조회, 2: 개수로 조회 + objStockChart.SetInputValue(2, today) # 기간 조회 시, 시작일 + objStockChart.SetInputValue(3, today) # 기간 조회 시, 종료일 + objStockChart.SetInputValue(4, 400) # 조회 시 가져오는 Line 개수 + objStockChart.SetInputValue(5, [0, 1, 2, 3, 4, 5, 8]) # 날짜,시간,시가,고가,저가,종가,거래량 + objStockChart.SetInputValue(6, ord('m')) # '차트 주가 - 월(M), 주(W), 일(D), 시(H), 분(m), 초(S) 차트 요청 + objStockChart.SetInputValue(7, 1) + objStockChart.SetInputValue(9, ord('1')) # 수정주가 사용 + objStockChart.BlockRequest() + + size = objStockChart.GetHeaderValue(3) + + today_str = "" + open, close, high, low, volume = 0, 0, 0, 9999999990, 0 + + #print("날짜", "시간", "시가", "고가", "저가", "종가", "거래량") + start_time = datetime.strptime(today + " 090000", '%Y%m%d %H%M%S') + # + # 역순으로 결과가 오는지 확인이 필요함 + # + for i in range(size-1, -1, -1): + int_day = objStockChart.GetDataValue(0, i) + int_time = objStockChart.GetDataValue(1, i) + # ymd: '2022.03.29' + # time = datetime.strptime(str(int_day)+" "+str(int_time).zfill(4)+"00", '%Y%m%d %H%M%S') + # time_str = time.strftime('%Y.%m.%d') + today_str = today[0:4] + "." + today[4:6] + "." + today[6:8] + + if i == 0: + open = objStockChart.GetDataValue(2, i) + if i == size - 1: + close = objStockChart.GetDataValue(5, i) + high = max(high, objStockChart.GetDataValue(3, i)) + low = min(low, objStockChart.GetDataValue(4, i)) + volume = volume + objStockChart.GetDataValue(6, i) + + stock['PRICE'].append( + { + "ymd": today_str, + "close": close, + "diff": -1, + "open": open, + "high": high, + "low": low, + "volume": volume, + "avg3": -1, + "avg4": -1, + "avg5": -1, + "avg6": -1, + "avg10": -1, + "avg12": -1, + "avg20": -1, + "avg36": -1, + "avg40": -1, + "avg48": -1, + "avg60": -1, + "avg120": -1, + "avg200": -1, + "avg240": -1, + "avg300": -1, + "disparity_avg5": -1, + "disparity_avg10": -1, + "disparity_avg20": -1, + "disparity_avg60": -1, + "disparity_avg120": -1, + "bolingerband_upper": -1, + "bolingerband_lower": -1, + "bolingerband_middle": -1, + "envelope_upper": -1, + "envelope_lower": -1, + "envelope_middle": -1, + "ichimokucloud_changeLine": -1, + "ichimokucloud_baseLine": -1, + "ichimokucloud_leadingSpan1": -1, + "ichimokucloud_leadingSpan2": -1, + "stochastic_fast_k": -1, + "stochastic_slow_k": -1, + "stochastic_slow_d": -1, + "rsi": -1, + "rsis": -1, + "macd": -1, + "macds": -1, + "macdo": -1, + } + ) + + return + def getClosePrice_realtime(self, stock_code, today): result = {"open": [], "close": [], "high": [], "low": [], "vol": []} diff --git a/stock/analysis/DailyStatus.py b/stock/analysis/DailyStatus.py index 0842181..6fdd4fe 100644 --- a/stock/analysis/DailyStatus.py +++ b/stock/analysis/DailyStatus.py @@ -633,11 +633,12 @@ class DailyStatus (HTS): else: n = 200 + today = datetime.today().strftime('%Y%m%d') + if stock_codes is not None: for stock_code in stock_codes: stock = self.getLastData(stock_code, n) - today = datetime.today().strftime('%Y%m%d') self.getData(today, stock) analyzed_day = 60 data = self.analyze(stock, analyzed_day) @@ -661,7 +662,6 @@ class DailyStatus (HTS): cursor.close() conn.close() - today = datetime.today().strftime('%Y%m%d') dailyDirName = os.path.join(self.RESOURCE_PATH, 'analysis', today, 'daily') if os.path.exists(dailyDirName): shutil.rmtree(dailyDirName) @@ -682,8 +682,6 @@ class DailyStatus (HTS): print("Analysis # :", idx, ", CODE: ", stock_code, ", NAME: ", stock_name) stock = self.getLastData(stock_code, n) - - today = datetime.today().strftime('%Y%m%d') self.getData(today, stock) analyzed_day = 60 data = self.analyze(stock, analyzed_day)