From c1ce87aa37731bfbb573f2af92ed64c2fb46488b Mon Sep 17 00:00:00 2001 From: dosangyoon Date: Sat, 16 Oct 2021 14:24:27 +0900 Subject: [PATCH] init --- hts/{BS.py => BuySellChecker.py} | 12 ++--- hts/HTS.py | 81 +++++++++++++++++--------------- hts/OrderChecker.py | 58 +++++++++++++++++++++++ hts/OrderItem.py | 25 ++++++++++ hts/OrderType.py | 8 ++++ hts/Simulation.py | 22 +++++---- 6 files changed, 152 insertions(+), 54 deletions(-) rename hts/{BS.py => BuySellChecker.py} (99%) create mode 100644 hts/OrderChecker.py create mode 100644 hts/OrderItem.py create mode 100644 hts/OrderType.py diff --git a/hts/BS.py b/hts/BuySellChecker.py similarity index 99% rename from hts/BS.py rename to hts/BuySellChecker.py index 173b3e3..b2bcd61 100644 --- a/hts/BS.py +++ b/hts/BuySellChecker.py @@ -3,7 +3,7 @@ from stockpredictor.analysis.Common import Common from stockpredictor.analysis.Stochastic import Stochastic from stockpredictor.analysis.RSI import RSI -class BS: +class BuySellChecker: common = None stochastic = None @@ -207,16 +207,16 @@ class BS: # rsi가 rsis 위로 올라오며 15 이하일 경우 10배로 주문함 (14:30 이전) if data["rsi"][i] < 15 and data["rsis"][i] < 15 and data["rsi"][i - 1] < data["rsis"][i - 1] and data["rsis"][i] < data["rsi"][i]: buy = data["Low"][i] - weight = 3 + weight = 4 if data["rsi"][i] < 10: - weight = 3 + weight = 4 if data["slow_k"][i] in (0, 1, 2, 3): - weight = 2.5 + weight = 3 if data["slow_k"][i] in (4, 5, 6, 7, 8): - weight = 2 + weight = 2.5 elif data["slow_k"][i] in (9, 10, 11, 12, 13): - weight = 1.5 + weight = 2 elif data["slow_k"][i] in (14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25): weight = 1 diff --git a/hts/HTS.py b/hts/HTS.py index 497fa33..09a5e52 100644 --- a/hts/HTS.py +++ b/hts/HTS.py @@ -1,29 +1,14 @@ import win32com.client import time import os -from datetime import datetime, timedelta +from datetime import datetime import pandas as pd -from enum import Enum -from BS import BS +from OrderType import OrderType +from OrderItem import OrderItem -# enum 주문 상태 세팅용 -class EorderBS(Enum): - buy = 1 # 매수 - sell= 2 # 매도 - none =3 - -class orderData: - def __init__(self): - self.dicEx = {EorderBS.buy: "매수", EorderBS.sell: "매도", EorderBS.none: "없음"} - self.orderNum = 0 - self.bs = EorderBS.none # 0 : buy 1: sell - self.code = "" - self.amount = 0 - self.price = 0 - - def debugPrint(self): - print(self.dicEx.get(self.bs), self.code, self.orderNum, self.amount, self.price) +from BuySellChecker import BuySellChecker +from OrderChecker import OrderChecker class HTS: @@ -31,10 +16,10 @@ class HTS: objCpCybos = None objCpCodeMgr = None - bs = None + buySellChecker = None def __init__(self): - self.bs = BS() + self.buySellChecker = BuySellChecker() #self.connect() return @@ -189,13 +174,13 @@ class HTS: nRet = objStockOrder.BlockRequest() if (nRet != 0): print("order error", nRet) - return + return None rqStatus = objStockOrder.GetDibStatus() rqRet = objStockOrder.GetDibMsg1() print("통신상태", rqStatus, rqRet) if rqStatus != 0: - return + return None orderNum = objStockOrder.GetHeaderValue(0) @@ -330,7 +315,7 @@ class HTS: break for i in range(cnt): - item = orderData() + item = OrderItem() item.orderNum = objResult.GetDataValue(1, i) item.orderPrev = objResult.GetDataValue(2, i) item.code = objResult.GetDataValue(3, i) # 종목코드 @@ -356,9 +341,7 @@ class HTS: return orderList # 미체결 취소하기 - def cancelOrderList(self): - #주문 리스트를 가져온다. - orderList = self.requestOrderList() + def cancelOrderList(self, orderList): if len(orderList) < 1: return @@ -534,7 +517,7 @@ class HTS: if i < 5: return -1, -1, -1 - buy, weight, sell = self.bs.getPriceAndWeight1(data, i) + buy, weight, sell = self.buySellChecker.getPriceAndWeight1(data, i) return buy, weight, sell def getSellingPrice(self, final_price): @@ -563,6 +546,9 @@ class HTS: return 0, 0 def buyRealTime(self, stock_code, given_day): + orderChecker = OrderChecker() + BASE_COUNT = 100 + timecheckList = pd.read_csv("timecheck.csv").values.tolist() timecheck = {given_day + " " + str(second).zfill(6):False for second, check in timecheckList} @@ -587,19 +573,25 @@ class HTS: self.getRealTime(stock_code, given_day, result) # 분석을 통해서 볼린저밴드 상/하단을 계산한다. - data = self.bs.analyze(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: - BUY_COUNT = int(200 * bs_weight) + # 기본 100 주에 가중치를 추가해서 매수한다. + BUY_COUNT = int(BASE_COUNT * bs_weight) - # 매수 전에 모든 미체결을 취소한다. - # self.cancelOrderList() - # 현재까지 매입금액이 7백만원 이하일 때만 매수를 한다. - self.requestOrder("2", stock_code, bs_weight * BUY_COUNT , bs_buy_price) + # 매수를 주문한다. + orderNum = self.requestOrder(OrderType.buy, stock_code, BUY_COUNT , bs_buy_price) + # 미체결 기록을 가져온다. + orderList = self.requestOrderList() + # 매수 주문을 기록한다. + orderListToCancel = orderChecker.add("2", orderNum, BUY_COUNT, bs_buy_price, orderList) + # 두 시간 이전 미체결을 취소한다. + self.cancelOrderList(orderListToCancel) + # 로그 출력 print("BUY", second, BUY_COUNT, bs_buy_price) if bs_sell_price > 0: @@ -607,20 +599,31 @@ class HTS: selling_count, selling_price = self.getSellingPrice(final_price) # 분석되 가격으로 매도 요청한다. if selling_count != 0 and selling_price != 0: - self.requestOrder("1", stock_code, selling_count, selling_price) + orderNum = self.requestOrder(OrderType.sell, stock_code, selling_count, selling_price) + # 미체결 기록을 가져온다. + orderList = self.requestOrderList() + # 매도 주문을 기록한다. + orderListToCancel = orderChecker.add(OrderType.sell, orderNum, selling_count, selling_price, orderList) + # 두 시간 이전 미체결을 취소한다. + self.cancelOrderList(orderListToCancel) + # 로그 출력 print("SELL", second, selling_count, selling_price) + # 로그 출력 print("TIMECHECK", second, final_price, data["Low"][data_size-1], data["slow_k"][data_size-1], data["slow_d"][data_size-1]) timecheck[second] = True if datetime.strptime(given_day + " 151000", '%Y%m%d %H%M%S') < datetime.now(): - # 15:10:00 이후라면 모든 미체결 취소 - self.cancelOrderList() + # 주문 리스트를 가져온다. + 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: - self.requestOrder("1", stock_code, selling_count, selling_price) + orderNum = self.requestOrder(OrderType.sell, stock_code, selling_count, selling_price) + # 로그 출력 print("SELL", second, selling_count, selling_price) break diff --git a/hts/OrderChecker.py b/hts/OrderChecker.py new file mode 100644 index 0000000..c3d5f6f --- /dev/null +++ b/hts/OrderChecker.py @@ -0,0 +1,58 @@ +import os +import pandas as pd +from datetime import datetime, timedelta + +from OrderItem import OrderItem + +class OrderChecker: + + order_df = None # 매수/매도구분, orderNum, 금액, 시각 + saveFileName = None + + def __init__(self): + self.saveFileName = "./order/"+datetime.today().strftime("%Y%m%d")+".csv" + self.read(self.saveFileName) + return + + def read(self, fileName): + if os.path.isfile(fileName): + self.order_df = pd.read_csv(fileName) + else: + self.order_df = None + + def add(self, type, orderNum, count, price, orderList): + orderListToCancel = [] + + if self.order_df is None: + self.order_df = pd.DataFrame() + else: + # 두 시간 전 + before_two_hour = datetime.now() - timedelta(hours=2) + + # 두 시간 전 주문을 찾는다. + if len(orderList) > 0: + # 만약 두시간 전 주문을 찾는다. + orderNum_df = self.order_df.loc[self.order_df["datetime"] <= before_two_hour] + orderNumSet = set(list(orderNum_df["orderNum"])) + for item in orderList: + if item.orderNum in orderNumSet: + orderListToCancel.append(item) + # 해당 orderNum 제외하기 + self.order_df = self.order_df.loc[self.order_df["orderNum"] != item.orderNum] + + self.order_df = self.order_df.append({"type": type, "orderNum": orderNum, "count": count, "price": price, "datetime": datetime.now()}, ignore_index=True) + self.order_df.to_csv(self.saveFileName) + + return orderListToCancel + +if __name__ == "__main__": + orderChecker = OrderChecker() + + a = pd.DataFrame(columns=["a", "b", "c", "d", "e"]) + a = a.append({"a": 0, "b": 1, "c": 3, "d": 7, "e": 8}, ignore_index=True) + a = a.append({"a": 1, "b": 3, "c": 0, "d": 6, "e": 6}, ignore_index=True) + a = a.append({"a": 2, "b": 3, "c": 0, "d": 3, "e": 9}, ignore_index=True) + a = a.append({"a": 3, "b": 9, "c": 9, "d": 8, "e": 4}, ignore_index=True) + + a = a.loc[a["c"] != 9] + print(a.tail()) \ No newline at end of file diff --git a/hts/OrderItem.py b/hts/OrderItem.py new file mode 100644 index 0000000..b6f0f6d --- /dev/null +++ b/hts/OrderItem.py @@ -0,0 +1,25 @@ +from OrderType import OrderType + +class OrderItem: + + def __init__(self): + self.dicEx = {OrderType.buy: "매수", OrderType.sell: "매도", OrderType.none: "없음"} + + self.orderNum = None + self.orderPrev = None + self.code = None # 종목코드 + self.name = None # 종목명 + self.orderDesc = None # 주문구분내용 + self.amount = None # 주문수량 + self.price = None # 주문단가 + self.ContAmount = None # 체결수량 + self.credit = None # 신용구분 + self.modAvali = None # 정정취소 가능수량 + self.buysell = None # 매매구분코드 + self.creditdate = None # 대출일 + self.orderFlagDesc = None # 주문호가구분코드내용 + self.orderFlag = None # 주문호가구분코드 + + + def debugPrint(self): + print(self.dicEx.get(self.buysell), self.code, self.orderNum, self.amount, self.price) diff --git a/hts/OrderType.py b/hts/OrderType.py new file mode 100644 index 0000000..5753812 --- /dev/null +++ b/hts/OrderType.py @@ -0,0 +1,8 @@ +from enum import Enum + +# enum 주문 상태 세팅용 +class OrderType(Enum): + + none = "0" # None + sell = "1" # 매도 + buy = "2" # 매수 diff --git a/hts/Simulation.py b/hts/Simulation.py index d383a61..6c86415 100644 --- a/hts/Simulation.py +++ b/hts/Simulation.py @@ -1,16 +1,16 @@ import os -from datetime import datetime, timedelta +from datetime import datetime import pandas as pd import plotly.graph_objects as go from plotly import subplots -from BS import BS +from BuySellChecker import BuySellChecker class Simulation: - bs = None + buySellChecker = None def __init__(self): - self.bs = BS() + self.buySellChecker = BuySellChecker() #self.connect() return @@ -50,7 +50,7 @@ class Simulation: bsLine['sell'] = [-1 for i in range(size)] for i in range(6, size-5): - buy, weight, sell = self.bs.getPriceAndWeight1(data, i) + buy, weight, sell = self.buySellChecker.getPriceAndWeight1(data, i) bsLine['buy'][i] = buy bsLine['weight'][i] = weight bsLine['sell'][i] = sell @@ -97,6 +97,7 @@ class Simulation: avg5 = go.Scatter(x=data['Date'], y=data["avg5"], name="avg5", line_color='#000000') 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') + volume_line = go.Scatter(x=data['Date'], y=data["Volume"], mode='lines', name='Volume') fast_k_line = go.Scatter(x=data['Date'], y=data["fast_k"], mode='lines', name='fast_k') slow_k_line = go.Scatter(x=data['Date'], y=data["slow_k"], mode='lines', name='slow_k') slow_d_line = go.Scatter(x=data['Date'], y=data["slow_d"], mode='lines', name='slow_d') @@ -105,6 +106,7 @@ class Simulation: #candle_data = [candle_stick, bolinger_upper, bolinger_lower, buy_check, sell_check, avg1, avg2, avg5, avg10, avg20, avg30, avg40, avg50, avg60] candle_data = [candle_stick, bolinger_upper, bolinger_lower, avg5, buy_check, sell_check] + volume_data = [volume_line] stochastic_data = [slow_k_line, slow_d_line] rsi_data = [rsi_line, rsis_line] @@ -115,13 +117,15 @@ class Simulation: fig.show() """ - fig = subplots.make_subplots(rows=3, cols=1, subplot_titles=('캔들', "스토캐스틱", "RSI")) + fig = subplots.make_subplots(rows=4, cols=1, subplot_titles=('캔들', "거래량", "스토캐스틱", "RSI")) for trace in candle_data: fig.append_trace(trace, 1, 1) - for trace in stochastic_data: + for trace in volume_data: fig.append_trace(trace, 2, 1) - for trace in rsi_data: + for trace in stochastic_data: fig.append_trace(trace, 3, 1) + for trace in rsi_data: + fig.append_trace(trace, 4, 1) #fig.update_xaxes(nticks=5) #fig.update_layout(height=1800, title=stock_code + "_" + given_day, xaxis_rangeslider_visible=False) fig.update_layout(height=1800, title=stock_code + "_" + given_day) @@ -142,7 +146,7 @@ class Simulation: self.getCSV("./data/"+stock_code+"_"+given_day+".csv", given_day, result) # 분석을 통해서 볼린저밴드 상/하단을 계산한다. - data = self.bs.analyze(result) + data = self.buySellChecker.analyze(result) # 사야 할 시점과 팔아야 할 시점을 체크한다. bsLine = self.checkTransaction(data)