import time import os from datetime import datetime import pandas as pd from hts.HTS import HTS from hts.OrderType import OrderType from hts.OrderItem import OrderItem from hts.BuySellChecker import BuySellChecker from hts.OrderChecker import OrderChecker class HTS_252670 (HTS): buySellChecker = None stock_code = None def __init__(self, stock_code): super().__init__() self.buySellChecker = BuySellChecker() self.stock_code = stock_code return # 주식 현재가 조회 def writeStockData(self, stock_code, given_day): objCpCybos = win32com.client.Dispatch("CpUtil.CpCybos") bConnect = objCpCybos.IsConnect if (bConnect == 0): print("PLUS가 정상적으로 연결되지 않음. ") exit() # 차트 객체 구하기 objStockChart = win32com.client.Dispatch("CpSysDib.StockChart") outfp = open("./data/"+stock_code+"_"+given_day+".csv", mode="w", encoding="utf-8") objStockChart.SetInputValue(0, 'A' + stock_code) # 종목 코드 objStockChart.SetInputValue(1, ord('1')) # 1: 기간으로 조회, 2: 개수로 조회 objStockChart.SetInputValue(2, given_day) # 기간 조회 시, 시작일 objStockChart.SetInputValue(3, given_day) # 기간 조회 시, 종료일 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) outfp.write("%s,%s,%s,%s,%s,%s,%s\n" % ("날짜", "시간", "시가", "고가", "저가", "종가", "거래량")) for i in range(size - 1, -1, -1): day = objStockChart.GetDataValue(0, i) time = objStockChart.GetDataValue(1, i) start = objStockChart.GetDataValue(2, i) high = objStockChart.GetDataValue(3, i) low = objStockChart.GetDataValue(4, i) close = objStockChart.GetDataValue(5, i) vol = objStockChart.GetDataValue(6, i) outfp.write("%d,%s,%d,%d,%d,%d,%d\n" % (day, str(time).zfill(4), start, high, low, close, vol)) outfp.close() return def write(self, day, result): #날짜,시간,시가,고가,저가,종가,거래량 #20210909,900,2070,2070,2070,2070,0 outFp = open(day+".csv", mode="w", encoding="UTF-8") outFp.write("날짜,시간,시가,고가,저가,종가,거래량\n") for i in range(len(result["time"])): outFp.write("%s,%s,%s,%s,%s,%s,%s\n"%( result["time"][i].strftime('%Y%m%d'), result["time"][i].strftime('%H%M'), result["open"][i], result["high"][i], result["low"][i], result["close"][i], result["vol"][i])) outFp.close() return # 주식 현재가 조회 def getRealTime(self, stock_code, given_day, result): int_given_day = int(given_day) 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, given_day) # 기간 조회 시, 시작일 objStockChart.SetInputValue(3, given_day) # 기간 조회 시, 종료일 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) #print("날짜", "시간", "시가", "고가", "저가", "종가", "거래량") start_time = datetime.strptime(given_day + " 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) if int_day < int_given_day: continue time = datetime.strptime(str(int_day)+" "+str(int_time).zfill(4)+"00", '%Y%m%d %H%M%S') if time < start_time: continue open = objStockChart.GetDataValue(2, i) close = objStockChart.GetDataValue(5, i) high = objStockChart.GetDataValue(3, i) low = objStockChart.GetDataValue(4, i) vol = objStockChart.GetDataValue(6, i) if len(result["check"]) == 0: result["check"].add(start_time) result["time"].append(start_time) result["open"].append(open) result["close"].append(open) result["high"].append(open) result["low"].append(open) result["vol"].append(0) if time not in result["check"]: result["check"].add(time) result["time"].append(time) result["open"].append(open) result["close"].append(close) result["high"].append(high) result["low"].append(low) result["vol"].append(vol) return def checkTransaction(self, data): size = len(data["close"]) bsLine = {} bsLine['buy'] = [-1 for i in range(size)] bsLine['weight'] = [-1 for i in range(size)] bsLine['sell'] = [-1 for i in range(size)] i = size - 1 if i < 5: return -1, -1, -1 buy, weight, sell = self.buySellChecker.getPriceAndWeight1(data, i) return buy, weight, sell def getSellingPrice(self, final_price): # 만약 잔고가 있으면 장부가보다 5원 높게 매도한다. jangoDic = self.requstJango() if jangoDic and len(jangoDic.keys()) > 0: for code in jangoDic: if jangoDic[code]['매도가능'] > 0: if final_price >= jangoDic[code]['장부가'] + 5: return jangoDic[code]['매도가능'], final_price else: # 장부가 가격의 마지막 자리를 0으로 만든다. (2090 -> 2090, 2092 -> 2090, 2098 -> 2090) sell_price = int(jangoDic[code]['장부가'] / 10) * 10 # 장부가의 마지막 자리수를 가져온다. last_number = int(jangoDic[code]['장부가']) % 10 if last_number in [0, 1, 2, 3]: # 장부가의 마지막 자리수가 0,1,2,3 이라면 (2090, 2091, 2092 -> 2095 에 매도) return jangoDic[code]['매도가능'], sell_price + 5 elif last_number in [4, 5, 6, 7]: # 장부가의 마지막 자리수가 4,5,6,7 이라면 (2093, 2094, 2095, 2096 -> 2100 에 매도) return jangoDic[code]['매도가능'], sell_price + 10 else: # 장부가의 마지막 자리수가 8,9 라면 (2098, 2099 -> 2105 에 매도) return jangoDic[code]['매도가능'], sell_price + 15 return 0, 0 def buyRealTime(self, GIVEN_DAY): orderChecker = OrderChecker(self.stock_code) BASE_COUNT = 500 timecheckList = pd.read_csv("timecheck.csv").values.tolist() timecheck = {GIVEN_DAY + " " + str(second).zfill(6):False for second, check in timecheckList} result = {"check": set(), "time": [], "open": [], "close": [], "high": [], "low": [], "vol": []} print ("START...") THIS_TIME = datetime.now() while datetime.strptime(GIVEN_DAY + " 070000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(GIVEN_DAY + " 15200", '%Y%m%d %H%M%S'): if datetime.strptime(GIVEN_DAY + " 090100", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(GIVEN_DAY + " 151500", '%Y%m%d %H%M%S'): if THIS_TIME.strftime('%Y%m%d %H%M%S') in timecheck and not timecheck[THIS_TIME.strftime('%Y%m%d %H%M%S')]: # 데이터를 가지고 온다. self.getRealTime(self.stock_code, GIVEN_DAY, result) # 분석을 통해서 볼린저밴드 상/하단을 계산한다. data = self.buySellChecker.analyze(result) # 사야 할 시점/가격과 팔아야 할 시점/가격을 체크한다. bs_buy_price, bs_weight, bs_sell_price = self.checkTransaction(data) data_size = len(data["close"]) final_price = data["close"][data_size-1] if bs_buy_price > 0: # 기본 100 주에 가중치를 추가해서 매수한다. #BUY_COUNT = int(BASE_COUNT * bs_weight) BUY_COUNT = int(BASE_COUNT * 1) # 매수를 주문한다. orderNum = self.requestOrder(OrderType.buy, self.stock_code, BUY_COUNT , bs_buy_price) # 미체결 기록을 가져온다. ORDER_LIST = self.requestOrderList() # 매수 주문을 기록한다. orderListToCancel = 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 = orderChecker.remove(self.stock_code, OrderType.sell, ORDER_LIST) # 매도 미체결을 모두 취소한다. self.cancelOrderList(orderListToCancel) # 매도 가격을 가져온다. selling_count, selling_price = self.getSellingPrice(final_price) # 분석되 가격으로 매도 요청한다. if selling_count != 0 and selling_price != 0: # 매도를 요청한다. orderNum = self.requestOrder(OrderType.sell, self.stock_code, selling_count, selling_price) # 로그 출력 print("SELL", THIS_TIME.strftime('%Y%m%d %H%M%S'), selling_count, selling_price, len(orderListToCancel), len(ORDER_LIST)) """ # 로그 출력 print("TIMECHECK: %s, price: %d, low: %d, lower: %.2f, avg5: %.2f, slow_k_1: %.2f, slow_d_1: %.2f, slow_k: %.2f, slow_d: %.2f, rsi: %.2f, rsis: %.2f" % (str(THIS_TIME), final_price, data["low"][data_size-1], data["lower"][data_size-1], data["avg5"][data_size-1], data["slow_k"][data_size-2], data["slow_d"][data_size-2], data["slow_k"][data_size-1], data["slow_d"][data_size-1], data["rsi"][data_size-1], data["rsis"][data_size-1])) timecheck[THIS_TIME] = True """ if datetime.strptime(GIVEN_DAY + " 151530", '%Y%m%d %H%M%S') < THIS_TIME: #### # 손해 보지 않는 가격에 매도한다. #### # 주문 리스트를 가져온다. orderList = self.requestOrderList() # 15:10:00 이후라면 모든 미체결 취소한다. self.cancelOrderList(orderList) # 매도 가격을 가져온다. selling_count, selling_price = self.getSellingPrice(final_price) # 분석되 가격으로 매도 요청한다. if selling_count != 0 and selling_price != 0: orderNum = self.requestOrder(OrderType.sell, self.stock_code, selling_count, selling_price) # 로그 출력 print("SELL", THIS_TIME, selling_count, selling_price) break """ time.sleep(0.9) THIS_TIME = datetime.now() return if __name__ == "__main__": today = datetime.today() PROJECT_HOME = os.path.join(os.path.dirname(os.path.join(os.path.dirname(__file__)))) RESOURCE_DIR = PROJECT_HOME + "/resources/analysis/"+today.strftime("%Y%m%d") # KODEX 인버스 * 2 stock_code = "252670" hts = HTS_252670(stock_code) given_day = datetime.today().strftime('%Y%m%d') #hts.writeStockData(stock_code, "20220520") hts.buyRealTime(given_day) print ("done...")