import win32com.client import time import os from datetime import datetime, timedelta import pandas as pd from enum import Enum #import plotly.graph_objects as go from stockpredictor.analysis.Common import Common # 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) class HTS: objCpCybos = None objCpCodeMgr = None common = None stock = [] def __init__(self): self.common = Common() #self.connect() return def connect(self): # 연결 여부 체크 self.objCpCybos = win32com.client.Dispatch("CpUtil.CpCybos") bConnect = self.objCpCybos.IsConnect if (bConnect == 0): print("PLUS가 정상적으로 연결되지 않음. ") exit() return def all_stocks(self): # 종목코드 리스트 구하기 self.objCpCodeMgr = win32com.client.Dispatch("CpUtil.CpCodeMgr") codeList = self.objCpCodeMgr.GetStockListByMarket(1) # 거래소 codeList2 = self.objCpCodeMgr.GetStockListByMarket(2) # 코스닥 print("거래소 종목코드", len(codeList)) for i, code in enumerate(codeList): secondCode = self.objCpCodeMgr.GetStockSectionKind(code) name = self.objCpCodeMgr.CodeToName(code) stdPrice = self.objCpCodeMgr.GetStockStdPrice(code) print(i, code, secondCode, stdPrice, name) print("코스닥 종목코드", len(codeList2)) for i, code in enumerate(codeList2): secondCode = self.objCpCodeMgr.GetStockSectionKind(code) name = self.objCpCodeMgr.CodeToName(code) stdPrice = self.objCpCodeMgr.GetStockStdPrice(code) print(i, code, secondCode, stdPrice, name) print("거래소 + 코스닥 종목코드 ", len(codeList) + len(codeList2)) return # 차트 데이터 구하기 def getChartData(self, stock_code): # 차트 객체 구하기 objStockChart = win32com.client.Dispatch("CpSysDib.StockChart") objStockChart.SetInputValue(0, 'A'+stock_code) # 종목 코드 - 삼성전자 objStockChart.SetInputValue(1, ord('2')) # 개수로 조회 objStockChart.SetInputValue(4, 100) # 최근 100일 치 objStockChart.SetInputValue(5, [0, 2, 3, 4, 5, 8]) # 날짜,시가,고가,저가,종가,거래량 objStockChart.SetInputValue(6, ord('D')) # '차트 주가 - 일간 차트 요청 objStockChart.SetInputValue(9, ord('1')) # 수정주가 사용 objStockChart.BlockRequest() len = objStockChart.GetHeaderValue(3) print("날짜", "시가", "고가", "저가", "종가", "거래량") print("==============================================-") for i in range(len): day = objStockChart.GetDataValue(0, i) open = objStockChart.GetDataValue(1, i) high = objStockChart.GetDataValue(2, i) low = objStockChart.GetDataValue(3, i) close = objStockChart.GetDataValue(4, i) vol = objStockChart.GetDataValue(5, i) print(day, open, high, low, close, vol) return # 주식 현재가 조회 def currentStock(self, stock_code): # 현재가 객체 구하기 self.objStockMst = win32com.client.Dispatch("DsCbo1.StockMst") self.objStockMst.SetInputValue(0, 'A'+stock_code) # 종목 코드 - 삼성전자 self.objStockMst.BlockRequest() # 현재가 통신 및 통신 에러 처리 rqStatus = self.objStockMst.GetDibStatus() rqRet = self.objStockMst.GetDibMsg1() print("통신상태", rqStatus, rqRet) if rqStatus != 0: exit() # 현재가 정보 조회 code = self.objStockMst.GetHeaderValue(0) # 종목코드 name = self.objStockMst.GetHeaderValue(1) # 종목명 time = self.objStockMst.GetHeaderValue(4) # 시간 cprice = self.objStockMst.GetHeaderValue(11) # 종가 diff = self.objStockMst.GetHeaderValue(12) # 대비 open = self.objStockMst.GetHeaderValue(13) # 시가 high = self.objStockMst.GetHeaderValue(14) # 고가 low = self.objStockMst.GetHeaderValue(15) # 저가 offer = self.objStockMst.GetHeaderValue(16) # 매도호가 bid = self.objStockMst.GetHeaderValue(17) # 매수호가 vol = self.objStockMst.GetHeaderValue(18) # 거래량 vol_value = self.objStockMst.GetHeaderValue(19) # 거래대금 # 예상 체결관련 정보 exFlag = self.objStockMst.GetHeaderValue(58) # 예상체결가 구분 플래그 exPrice = self.objStockMst.GetHeaderValue(55) # 예상체결가 exDiff = self.objStockMst.GetHeaderValue(56) # 예상체결가 전일대비 exVol = self.objStockMst.GetHeaderValue(57) # 예상체결수량 print("코드", code) print("이름", name) print("시간", time) print("종가", cprice) print("대비", diff) print("시가", open) print("고가", high) print("저가", low) print("매도호가", offer) print("매수호가", bid) print("거래량", vol) print("거래대금", vol_value) if (exFlag == ord('0')): print("장 구분값: 동시호가와 장중 이외의 시간") elif (exFlag == ord('1')): print("장 구분값: 동시호가 시간") elif (exFlag == ord('2')): print("장 구분값: 장중 또는 장종료") print("예상체결가 대비 수량") print("예상체결가", exPrice) print("예상체결가 대비", exDiff) print("예상체결수량", exVol) return # 주식 현금 매수주문 def requestOrder(self, type, stock_code, count, price): # type = 2: buy, type=1: sell # 주문 초기화 objTrade = win32com.client.Dispatch("CpTrade.CpTdUtil") initCheck = objTrade.TradeInit(0) if (initCheck != 0): print("주문 초기화 실패") exit() # 주식 매수 주문 acc = objTrade.AccountNumber[0] # 계좌번호 accFlag = objTrade.GoodsList(acc, 1) # 주식상품 구분 # acc = "782446178" # accFlag[0] = "01" objStockOrder = win32com.client.Dispatch("CpTrade.CpTd0311") objStockOrder.SetInputValue(0, type) # 1: 매도, 2: 매수 objStockOrder.SetInputValue(1, acc) # 계좌번호 objStockOrder.SetInputValue(2, accFlag[0]) # 상품구분 - 주식 상품 중 첫번째 objStockOrder.SetInputValue(3, "A"+stock_code) # 종목코드 objStockOrder.SetInputValue(4, count) # 매수수량 count주 objStockOrder.SetInputValue(5, price) # 주문단가 - price 원 objStockOrder.SetInputValue(7, "0") # 주문 조건 구분 코드, 0: 기본 1: IOC 2:FOK objStockOrder.SetInputValue(8, "01") # 주문호가 구분코드 - 01: 보통 # 매수 주문 요청 nRet = objStockOrder.BlockRequest() if (nRet != 0): print("order error", nRet) return rqStatus = objStockOrder.GetDibStatus() rqRet = objStockOrder.GetDibMsg1() print("통신상태", rqStatus, rqRet) if rqStatus != 0: return orderNum = objStockOrder.GetHeaderValue(0) if (type == "1"): print ("(SELL", count, price, ")") else: print ("(BUY", count, price, ")") return orderNum # 계좌 잔고 확인 def requstJango(self): jangoDic = {} objTrade = win32com.client.Dispatch("CpTrade.CpTdUtil") initCheck = objTrade.TradeInit(0) if (initCheck != 0): print("주문 초기화 실패") exit() # 주식 매수 주문 acc = objTrade.AccountNumber[0] # 계좌번호 accFlag = objTrade.GoodsList(acc, 1) # 주식상품 구분 objRq = win32com.client.Dispatch("CpTrade.CpTd6033") objRq.SetInputValue(0, acc) # 계좌번호 objRq.SetInputValue(1, accFlag[0]) # 상품구분 - 주식 상품 중 첫번째 objRq.SetInputValue(2, 50) # 요청 건수(최대 50) dicflag1 = {ord(' '): '현금', ord('Y'): '융자', ord('D'): '대주', ord('B'): '담보', ord('M'): '매입담보', ord('P'): '플러스론', ord('I'): '자기융자', } while True: objRq.BlockRequest() # 통신 및 통신 에러 처리 rqStatus = objRq.GetDibStatus() rqRet = objRq.GetDibMsg1() #print("통신상태", rqStatus, rqRet) if rqStatus != 0: return False cnt = objRq.GetHeaderValue(7) if cnt > 3: return jangoDic for i in range(cnt): item = {} code = objRq.GetDataValue(12, i) # 종목코드 item['종목코드'] = code item['종목명'] = objRq.GetDataValue(0, i) # 종목명 item['대출일'] = objRq.GetDataValue(2, i) # 대출일 item['잔고수량'] = objRq.GetDataValue(7, i) # 체결잔고수량 item['매도가능'] = objRq.GetDataValue(15, i) item['장부가'] = objRq.GetDataValue(17, i) # 체결장부단가 # item['평가금액'] = self.objRq.GetDataValue(9, i) # 평가금액(천원미만은 절사 됨) # item['평가손익'] = self.objRq.GetDataValue(11, i) # 평가손익(천원미만은 절사 됨) # 매입금액 = 장부가 * 잔고수량 item['매입금액'] = item['장부가'] * item['잔고수량'] item['현재가'] = 0 item['대비'] = 0 item['거래량'] = 0 # 잔고 추가 # key = (code, item['현금신용'],item['대출일'] ) key = code jangoDic[key] = item if len(jangoDic) >= 3: # 최대 3 종목만, break if len(jangoDic) >= 3: break if (objRq.Continue == False): break check = False for item in jangoDic: if item: check = True break if not check: return None return jangoDic # 예약 주문 내역 조회 및 미체결 리스트 구하기 def requestOrderList(self): # type = 2: buy, type=1: sell orderList = [] # 주문 초기화 objTrade = win32com.client.Dispatch("CpTrade.CpTdUtil") initCheck = objTrade.TradeInit(0) if (initCheck != 0): print("주문 초기화 실패") exit() # 주식 매수 주문 acc = objTrade.AccountNumber[0] # 계좌번호 accFlag = objTrade.GoodsList(acc, 1) # 주식상품 구분 objResult = win32com.client.Dispatch("CpTrade.CpTd9065") objResult.SetInputValue(0, acc) # 계좌번호 objResult.SetInputValue(1, accFlag[0]) # 상품구분 - 주식 상품 중 첫번째 objResult.SetInputValue(2, 20) while True: objResult.BlockRequest() if objResult.GetDibStatus() != 0: print("통신상태", objResult.GetDibStatus(), objResult.GetDibMsg1()) return False cnt = objResult.GetHeaderValue(4) if cnt == 0: break for i in range(cnt): i1 = objResult.GetDataValue(1, i) # 주문구분(매수 또는 매도) i2 = objResult.GetDataValue(2, i) # 코드 i3 = objResult.GetDataValue(3, i) # 주문 수량 i4 = objResult.GetDataValue(4, i) # 주문호가구분 i5 = objResult.GetDataValue(6, i) # 예약번호 i6 = objResult.GetDataValue(12, i) # 처리구분내용 - 주문취소 또는 주문예정 i7 = objResult.GetDataValue(9, i) # 주문단가 i8 = objResult.GetDataValue(11, i) # 주문번호 i9 = objResult.GetDataValue(12, i) # 처리구분코드 i10 = objResult.GetDataValue(13, i) # 거부코드 i11 = objResult.GetDataValue(14, i) # 거부내용 print(i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11) # 미체결 if (i6 == "주문예정"): item = orderData() item.orderNum = i5 if (i1 == "매수"): item.bs = EorderBS.buy else: item.bs = EorderBS.sell item.code = i2 item.amount = i3 item.price = i7 orderList.append(item) # 연속 처리 체크 - 다음 데이터가 없으면 중지 if objResult.Continue == False: break return orderList # 주식 현재가 조회 def writeStockData(self, stock_codes, given_day): objCpCybos = win32com.client.Dispatch("CpUtil.CpCybos") bConnect = objCpCybos.IsConnect if (bConnect == 0): print("PLUS가 정상적으로 연결되지 않음. ") exit() # 차트 객체 구하기 objStockChart = win32com.client.Dispatch("CpSysDib.StockChart") for stock_code in stock_codes: 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 getCSV(self, fileName, given_day, result): data = pd.read_csv(fileName) days = data.날짜 time = data.시간 open = data.시가 close = data.종가 high = data.고가 low = data.저가 vol = data.거래량 start_time = datetime.strptime(given_day + " 090000", '%Y%m%d %H%M%S') for i in range(len(data)): temp = datetime.strptime(str(days[i]) + " " + str(time[i]).zfill(4)+"00", '%Y%m%d %H%M%S') if temp < start_time: continue if temp not in result["check"]: result["check"].add(temp) result["time"].append(temp) result["open"].append(open[i]) result["close"].append(close[i]) result["high"].append(high[i]) result["low"].append(low[i]) result["vol"].append(vol[i]) return def analyze(self, result): df = pd.DataFrame(result["close"]) max20 = df.rolling(window=10).mean() stddev20 = df.rolling(window=10).std() upper_df = max20 + (stddev20 * 2) # 상단 볼린저 밴드 lower_df = max20 - (stddev20 * 2) # 하단 볼린저 밴드 size = len(result["open"]) window = 5 open = result["open"] close = result["close"] high = result["high"] low = result["low"] vol = result["vol"] close_df = pd.DataFrame(close) avg5_list = close_df.rolling(window=3).mean().fillna(close[0]).values.tolist() avg5 = [item[0] for item in avg5_list] avg20_list = close_df.rolling(window=5).mean().fillna(close[0]).values.tolist() avg20 = [item[0] for item in avg20_list] avg60_list = close_df.rolling(window=10).mean().fillna(close[0]).values.tolist() avg60 = [item[0] for item in avg60_list] avg120_list = close_df.rolling(window=20).mean().fillna(close[0]).values.tolist() avg120 = [item[0] for item in avg120_list] avg240_list = close_df.rolling(window=40).mean().fillna(close[0]).values.tolist() avg240 = [item[0] for item in avg240_list] upper, lower = [], [] for i in range(len(upper_df)): if i < window: upper.append(upper_df.values[window - 1][0]) lower.append(lower_df.values[window - 1][0]) else: upper.append(upper_df.values[i][0]) lower.append(lower_df.values[i][0]) point_temp = result["time"] temp = {"Date": point_temp, "Open": open, "High": high, "Low": low, "Close": close, "Volume": vol, "avg5": avg5, "avg20": avg20, "avg60": avg60, "avg120": avg120, "avg240": avg240} data = pd.DataFrame(temp) df_final_time = pd.DatetimeIndex(point_temp) data.index = df_final_time return data, upper, lower def draw(self, stock_code, given_day, data, upper, lower, bsLine): buy_line = bsLine['buy'] sell_line = bsLine['sell'] # 그래프 설정을 위한 변수를 생성한다. data['Open'] = pd.to_numeric(data['Open']) data['High'] = pd.to_numeric(data['High']) data['Low'] = pd.to_numeric(data['Low']) data['Close'] = pd.to_numeric(data['Close']) data['Volume'] = pd.to_numeric(data['Volume']) data['avg5'] = pd.to_numeric(data['avg5']) data['avg20'] = pd.to_numeric(data['avg20']) data['avg60'] = pd.to_numeric(data['avg60']) data['avg120'] = pd.to_numeric(data['avg120']) data['avg240'] = pd.to_numeric(data['avg240']) buy_colors = [] for i in range(len(buy_line)): if buy_line[i] < 0: buy_colors.append("#ffffff") buy_line[i] = lower[0] else: buy_colors.append("#ff00ff") sell_colors = [] for i in range(len(sell_line)): if sell_line[i] < 0: sell_colors.append("#ffffff") sell_line[i] = lower[0] else: sell_colors.append("#00ced1") # 그래프를 설정한다. buy_check = go.Scatter(x=data['Date'], y=buy_line, mode='markers', name="buy", marker=dict(size=14, 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)) bolinger_upper = go.Scatter(x=data['Date'], y=upper, name="upper", line_color='#8B4513') bolinger_lower = go.Scatter(x=data['Date'], y=lower, name="lower", line_color='#8B4513') avg5 = go.Scatter(x=data['Date'], y=data['avg5'], name="avg5", line_color='#FF0000') avg20 = go.Scatter(x=data['Date'], y=data['avg20'], name="avg20", line_color='#F43B86') avg60 = go.Scatter(x=data['Date'], y=data['avg60'], name="avg60", line_color='#F0A500') avg120 = go.Scatter(x=data['Date'], y=data['avg120'], name="avg120", line_color='#14279B') avg240 = go.Scatter(x=data['Date'], y=data['avg240'], name="avg240", 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') # 그래프를 그린다. fig = go.Figure(data=[candle_stick, bolinger_upper, bolinger_lower, buy_check, sell_check, avg5, avg20, avg60, avg120, avg240]) fig.update_layout(title=stock_code + "_" + given_day) fig.show() return def checkStatus(self, STOCK, last_index): status = set() # 정배열 체크 temp_status = self.common.check_RightArrange(STOCK, last_index) if temp_status != "": status.add(temp_status) # 20일선 돌파 temp_status = self.common.check_Dolpa_Jiji(STOCK, last_index, '20') if temp_status != "": status.add(temp_status) # 60일선 돌파 temp_status = self.common.check_Dolpa_Jiji(STOCK, last_index, '60') if temp_status != "": status.add(temp_status) # 120일선 돌파 temp_status = self.common.check_Dolpa_Jiji(STOCK, last_index, '120') if temp_status != "": status.add(temp_status) # 240일선 돌파 temp_status = self.common.check_Dolpa_Jiji(STOCK, last_index, '240') if temp_status != "": status.add(temp_status) # 20일선 지지 매수가 추천 temp_status = self.common.check_Dolpa_Jiji_20(STOCK, last_index) if temp_status != "": status.add(temp_status) # 음봉인데 어제보다 종가가 더 높은 경우 # 이 경우 정배열 상태인지도 함께 체크를 한다. higher_umbong_status = self.common.checkHigherUmbong(STOCK, last_index) if higher_umbong_status != "": status.add(temp_status) # GOLDENCROSS#1은 바로 매수하지 않고, 이 시점 이후로 5일선이 20일선을 하방으로 뚫었다가 다시 20일선을 상방으로 뚫는 순간 매수를 시도한다. # GOLDENCROSS#2은 바로 매수 가능 # GOLDENCROSS#3은 바로 매수 가능 temp_status = self.common.check_golded_cross(STOCK, last_index) if temp_status != "": status.add(temp_status) # YANGBONG # 어제 음봉 이후 장대양봉이었다면, 매수 temp_status = self.common.checkLongYangBongAfterUmBong(STOCK, last_index) if temp_status != "": status.add(temp_status) # Doji # 하락 추세에서 도지가 나오면 매수 temp_status = self.common.checkDoji(STOCK, last_index) if temp_status != "": status.add(temp_status) # Gravestone # 상승 추세에서 그레이브스톤이 나오면 매도 temp_status = self.common.checkGravestone(STOCK, last_index) if temp_status != "": status.add(temp_status) # Dragonfly # 하락 추세에서 드레곤플라이가 나오면 매수 temp_status = self.common.checkDragonfly(STOCK, last_index) if temp_status != "": status.add(temp_status) # Hammer temp_status = self.common.checkHammer(STOCK, last_index) # 하락 추세에서 해머가 나오면 매수 if temp_status != "": status.add(temp_status) # Hangingman temp_status = self.common.checkHangingman(STOCK, last_index) # 상승 추세에서 행잉맨이 나오면 매도 if temp_status != "": status.add(temp_status) # 상승장악형 (Engulfing) - 다음 날도 양봉이라면 매수 # 하락 추세에서 상승장악형이 나오면 매수 temp_status = self.common.checkEngulfingHigh(STOCK, last_index) if temp_status != "": status.add(temp_status) # 하락장악형 (Engulfing) # 상승 추세에서 하락장악형이 나오면 매도 temp_status = self.common.checkEngulfingLow(STOCK, last_index) if temp_status != "": status.add(temp_status) # 상승 포아형 (Harami) # 하락 추세에서 상승포아형이 나오면 매수 temp_status = self.common.checkHaramiHigh(STOCK, last_index) if temp_status != "": status.add(temp_status) # 하락 포아형 (Harami) # 상승 추세에서 하락포아형이 나오면 매도 temp_status = self.common.checkHaramiLow(STOCK, last_index) if temp_status != "": status.add(temp_status) # 관통형 (piercing) # 하락 추세에서 관통형이 나오면 매수 temp_status = self.common.checkPiercing(STOCK, last_index) if temp_status != "": status.add(temp_status) # 흑운형 (Dark-cloud) # 상승 추세에서 흑운형이 나오면 매도 temp_status = self.common.checkDarkCloud(STOCK, last_index) if temp_status != "": status.add(temp_status) # 샛별 (Morning start) # 하락 추세에서 샛별형이 나오면 매수 temp_status = self.common.checkMorningstar(STOCK, last_index) if temp_status != "": status.add(temp_status) # 저녁별 (Evening start) # 상승 추세에서 저녁별형이 나오면 매도 temp_status = self.common.checkEveningstar(STOCK, last_index) if temp_status != "": status.add(temp_status) return status def checkTransaction_Realtime(self, data, upper, lower): size = len(data["Close"]) STOCK = [] for i in range(size): STOCK.append({'close': data["Close"][i], 'open': data["Open"][i], 'high': data["High"][i], 'low': data["Low"][i], 'avg5': data["avg5"][i], 'avg20': data["avg20"][i], 'avg60': data["avg60"][i], 'avg120': data["avg120"][i]}) bsLine = {} bsLine['buy'] = [-1 for i in range(len(lower))] bsLine['sell'] = [-1 for i in range(len(lower))] i = size - 1 status = self.checkStatus(STOCK, i) count_1 = 0 if "arrange_" in status: count_1 += 1 if "arrange_" in status and "HIGHERUMBONG_" in status: count_1 += 1 if "20_" in status: count_1 += 1 if "60_" in status: count_1 += 1 if "120_" in status: count_1 += 1 if "240_" in status: count_1 += 1 if "5-20_" in status: count_1 += 1 if "GOLDEN#2_" in status: count_1 += 1 if "GOLDEN#3_" in status: count_1 += 1 if "UMYANG_" in status: count_1 += 1 if "DOJI_" in status: count_1 += 1 if "DRAGONEFLY_" in status: count_1 += 1 if "HAMMER_" in status: count_1 += 1 if "ENHIGH_" in status: count_1 += 1 if "HAHIGH_" in status: count_1 += 1 if "PIERCING_" in status: count_1 += 1 if "MORNINGSTAR_" in status: count_1 += 1 count_0 = 0 if "GRAVESTONE_" in status: count_0 += 1 if "HANGINGMAN_" in status: count_0 += 1 if "ENLOW_" in status: count_0 += 1 if "HALOW_" in status: count_0 += 1 if "DARKCLOUD_" in status: count_0 += 1 if "EVENINGSTAR" in status: count_0 += 1 if count_0 == 0 and count_1 > 0: bsLine['buy'][i + 1] = STOCK[i]['close'] - 5 bsLine['sell'][i + 1] = STOCK[i]['close'] if count_0 > 0: bsLine['sell'][i + 1] = STOCK[i]['close'] + 5 return bsLine def checkTransaction_Simulation(self, data, upper, lower): size = len(data["Close"]) STOCK = [] for i in range(size): STOCK.append({'close': data["Close"][i], 'open': data["Open"][i], 'high': data["High"][i], 'low': data["Low"][i], 'volume':data["Volume"][i], 'avg5': data["avg5"][i], 'avg20': data["avg20"][i], 'avg60': data["avg60"][i], 'avg120': data["avg120"][i], 'avg240': data["avg240"][i]}) bsLine = {} bsLine['buy'] = [-1 for i in range(len(lower))] bsLine['sell'] = [-1 for i in range(len(lower))] for i in range(5, size-1): status = self.checkStatus(STOCK, i) count_1 = 0 if "arrange_" in status: count_1 += 1 if "arrange_" in status and "HIGHERUMBONG_" in status: count_1 += 1 if "20_" in status: count_1 += 1 if "60_" in status: count_1 += 1 if "120_" in status: count_1 += 1 if "240_" in status: count_1 += 1 if "5-20_" in status: count_1 += 1 if "GOLDEN#2_" in status: count_1 += 1 if "GOLDEN#3_" in status: count_1 += 1 if "UMYANG_" in status: count_1 += 1 if "DOJI_" in status: count_1 += 1 if "DRAGONEFLY_" in status: count_1 += 1 if "HAMMER_" in status: count_1 += 1 if "ENHIGH_" in status: count_1 += 1 if "HAHIGH_" in status: count_1 += 1 if "PIERCING_" in status: count_1 += 1 if "MORNINGSTAR_" in status: count_1 += 1 count_0 = 0 if "GRAVESTONE_" in status: count_0 += 1 if "HANGINGMAN_" in status: count_0 += 1 if "ENLOW_" in status: count_0 += 1 if "HALOW_" in status: count_0 += 1 if "DARKCLOUD_" in status: count_0 += 1 if "EVENINGSTAR" in status: count_0 += 1 if count_0 == 0 and count_1 > 0: bsLine['buy'][i + 1] = STOCK[i]['close'] - 5 bsLine['sell'][i + 1] = STOCK[i]['close'] if count_0 > 0: bsLine['sell'][i+1] = STOCK[i]['close'] + 5 return bsLine def simulate(self, stock_code, given_day): #timecheckList = pd.read_csv("timecheck.csv").values.tolist() #timecheck = {datetime.strptime(given_day + " " + str(second).zfill(6), '%Y%m%d %H%M%S'): False for second, check in timecheckList} result = {"check": set(), "time": [], "open": [], "close": [], "high": [], "low": [], "vol": []} # 데이터를 가지고 온다. self.getCSV("./data/"+stock_code+"_"+given_day+".csv", given_day, result) # 분석을 통해서 볼린저밴드 상/하단을 계산한다. data, upper, lower = self.analyze(result) # 사야 할 시점과 팔아야 할 시점을 체크한다. bsLine = self.checkTransaction_Simulation(data, upper, lower) # 그래프를 그린다. self.draw(stock_code, given_day, data, upper, lower, bsLine) # 가져온 만큼 데이터를 누적해서 파일로 작성한다. self.write(given_day, result) return def buyRealTime(self, stock_code, given_day): data, upper, lower = None, None, None previous_price = 0 buy_count = 260 total_byu_amt = 0 logFp = open(given_day+".log", "w") 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": []} while datetime.strptime(given_day + " 083000", '%Y%m%d %H%M%S') < datetime.now() < datetime.strptime(given_day + " 151000", '%Y%m%d %H%M%S'): second = datetime.now().strftime('%Y%m%d %H%M%S') if second in timecheck and not timecheck[second]: print("TIMECHECK", second) logFp.write("%s,%s,\n" %("TIMECHECK", second)) logFp.flush() # 데이터를 가지고 온다. self.getRealTime(stock_code, given_day, result) # 분석을 통해서 볼린저밴드 상/하단을 계산한다. data, upper, lower = self.analyze(result) # 사야 할 시점과 팔아야 할 시점을 체크한다. bsLine = self.checkTransaction_Realtime(data, upper, lower) buy_line = bsLine['buy'] # 주문 및 매도 처리 price = bsLine['buy'][len(buy_line)-1] # 매수신청과 5원 높여서 매도신청 if price > 0: if previous_price > 0: if previous_price > price: if buy_count < 200: buy_count = 200 buy_count += 40 if buy_count > 500: buy_count = 500 elif previous_price < price: if buy_count > 400: buy_count = 400 buy_count -= 40 if buy_count < 100: buy_count = 100 previous_price = price # 매수 주문 # 현재까지 매입금액이 7백만원 이하일 때만 매수를 한다. if total_byu_amt < 7000000: self.requestOrder("2", stock_code, buy_count , price) ## 매도 주문 (아래 잔고를 체크해서 매도를 호출하는 것으로 시도한다.) #time.sleep(60) #self.requestOrder("1", stock_code, buy_count , price + 5) print("BUY", second, price) logFp.write("%s,%s, %d\n" % ("BUY", second, price)) logFp.flush() # 가져온 만큼 데이터를 누적해서 파일로 작성한다. self.write(given_day, result) timecheck[second] = True else: #print("NONE", second) logFp.write("%s,%s,\n" % ("NONE", second)) logFp.flush() # 만약 잔고가 있으면 장부가보다 5원 높게 매도한다. jangoDic = self.requstJango() if jangoDic and len(jangoDic.keys()) > 0: for code in jangoDic: total_byu_amt = jangoDic[code]['매입금액'] if jangoDic[code]['매도가능'] > 0: # 장부가 가격의 마지막 자리를 0으로 만든다. (2090 -> 2090, 2092 -> 2090, 2098 -> 2090) sell_price = int(jangoDic[code]['장부가'] / 10) * 10 """ # 만약 오후 1시 이전이라면 한 호가 (5원) 더 올려서 매도한다. if datetime.strptime(given_day + " 092000", '%Y%m%d %H%M%S') < datetime.now() < datetime.strptime(given_day + " 104000", '%Y%m%d %H%M%S'): lower_size = len(lower) if lower != None and lower_size > 3: if lower[lower_size-3] < lower[lower_size-2] < lower[lower_size-1]: sell_price += 5 """ # 장부가의 마지막 자리수를 가져온다. last_number = int(jangoDic[code]['장부가']) % 10 if last_number in [0, 1, 2]: # 장부가의 마지막 자리수가 0,1,2 라면 (2090, 2091, 2092 -> 2095 에 매도) self.requestOrder("1", stock_code, jangoDic[code]['매도가능'], sell_price + 5) elif last_number in [3, 4, 5, 6]: # 장부가의 마지막 자리수가 3,4,5,6 라면 (2093, 2094, 2095, 2096 -> 2100 에 매도) self.requestOrder("1", stock_code, jangoDic[code]['매도가능'], sell_price + 10) else: # 장부가의 마지막 자리수가 7,8,9 라면 (2097, 2098, 2099 -> 2105 에 매도) self.requestOrder("1", stock_code, jangoDic[code]['매도가능'], sell_price + 15) time.sleep(0.9) logFp.close() 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") stock_codes = ["252670", "122630"] given_day = datetime.today().strftime('%Y%m%d') hts = HTS() #hts.all_stocks() #hts.getChartData(stock_codes) #hts.currentStock(stock_codes) given_days = ['20210901','20210902','20210903','20210906','20210907','20210908','20210909','20210910','20210913','20210914','20210915','20210916','20210917','20210923','20210924','20210927','20210928','20210929','20210930','20211001'] for given_day in given_days: hts.writeStockData(stock_codes, given_day) #for stock_code in stock_codes: #hts.simulate(stock_code, given_day) #hts.buyRealTime(stock_codes, given_day) print ("done...")