diff --git a/HTS_etf_122630.py b/HTS_etf_122630.py new file mode 100644 index 0000000..5177b4e --- /dev/null +++ b/HTS_etf_122630.py @@ -0,0 +1,224 @@ +import time +import os +import math +import sqlite3 +from datetime import datetime, timedelta + +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 +from stock.util.SlackBot import SlackBot +from stock.analysis.StockStatus import StockStatus + + +class HTS_etf(HTS): + RESOURCE_PATH = None + stock_code = None + buy_count = None + orderChecker = None + buySellChecker = None + labelChecker = None + slackBot = None + stockStatus = None + + def __init__(self, RESOURCE_PATH): + super().__init__(RESOURCE_PATH) + + self.RESOURCE_PATH = RESOURCE_PATH + + self.orderChecker = OrderChecker(self.RESOURCE_PATH, "ETF") + self.buySellChecker = BuySellChecker() + self.labelChecker = LabelChecker(RESOURCE_PATH) + self.slackBot = SlackBot() + self.stockStatus = StockStatus(RESOURCE_PATH) + + return + + def connect2StockDB(self): + + self.conn_stock = sqlite3.connect(os.path.join(self.RESOURCE_PATH, "resources/stock.db")) + self.cursor_stock = self.conn_stock.cursor() + + return + + def disconnectStockDB(self): + + self.cursor_stock.close() + self.conn_stock.close() + return + + def sellStocks(self, stock_code=None, bs_sell_price=None): + check = False + jangoDic = self.requstJango() + if jangoDic and len(jangoDic.keys()) > 0: + for code in jangoDic: + if stock_code is not None: + if code == "A" + stock_code and bs_sell_price is not None: + if jangoDic[code]['매도가능'] > 0: + if 2 < jangoDic[code]['평가손익']: + # 2% 이상 시 수익 매도 + self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], bs_sell_price) + self.slackBot.post_to_slack(code, jangoDic[code]['종목명'], "SELL", bs_sell_price, jangoDic[code]['매도가능']) + check = True + else: + continue + else: + if jangoDic[code]['매도가능'] > 0: + if 2 < jangoDic[code]['평가손익']: + # 2% 이상 시 수익 매도 + currentStock = self.currentStock(code[1:]) + self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], currentStock['close']) + self.slackBot.post_to_slack(code, jangoDic[code]['종목명'], "SELL", currentStock['close'], jangoDic[code]['매도가능']) + check = True + return check + + 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이면 장부가로 팔겠다는 의미임 + orderNum = None + jangoDic = self.requstJango() + if jangoDic and len(jangoDic.keys()) > 0: + for code in jangoDic: + if jangoDic[code]['매도가능'] > 0: + if without_loss: + if jangoDic[code]['장부가'] * 0.07 < jangoDic[code]['장부가'] - final_price: + sell_price = jangoDic[code]['장부가'] + if code == "A" + stock_code: + orderNum = self.requestOrder(OrderType.sell, stock_code, jangoDic[code]['매도가능'], sell_price) + return orderNum, 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) + return orderNum, log_time.strftime('%Y%m%d %H%M%S'), jangoDic[code]['매도가능'], sell_price + return orderNum, None, None, None + + def makeTickData(self, data, mins=30): + result = {"check": set(), + "time": [], + "open": [], + "close": [], + "high": [], + "low": [], + "vol": [], + "label": []} + + for i in range(mins, len(data['time']) + 1): + result["check"].add(data['time'][i - 1]) + result["time"].append(data['time'][i - 1]) + + result["open"].append(data['open'][i - mins]) + result["close"].append(data['close'][i - 1]) + result["high"].append(max(data['high'][i - mins: i])) + result["low"].append(min(data['low'][i - mins: i])) + result["vol"].append(sum(data['vol'][i - mins: i])) + + return result + + def buyRealTime(self, today, stock_code, analyzed_day=1000): + MAX_PRICE = 10000 + + print("START...") + THIS_TIME = datetime.now() + + LAST_DATA = self.getLastData(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'): + + # 매도를 체크한다. + self.sellStocks() + + time.sleep(0.1) + + try: + # 데이터를 가지고 온다. + result = self.getRealTime(stock_code, today, LAST_DATA) + except: + print("#ERROR:", stock_code) + continue + + data = self.buySellChecker.analyze(result) + data.drop(data.index[:len(data) - analyzed_day], inplace=True) + + # 사야 할 시점과 팔아야 할 시점을 체크한다. + bsLine = self.buySellChecker.checkTransaction(stock_code, data, None, None, isRealTime=True) + bs_buy_price = bsLine['buy'][0] + bs_buy_weight = bsLine['buy_weight'][0] + bs_sell_price = bsLine['sell'][0] + + # 미체결 기록을 가져와서 10분 이상 된 매수 주문을 취소 한다. + ORDER_LIST = self.requestOrderList() + orderListToCancel = self.orderChecker.cancel(today, "A" + stock_code, ORDER_LIST, mins=10) + if len(orderListToCancel) > 0: + self.cancelOrderList(orderListToCancel) + + if bs_buy_price > 1000: + + if not self.orderChecker.exist(today, "A" + stock_code, hours=9): + buy_count = int(MAX_PRICE / bs_buy_price) + + if buy_count > 0: + # 매수를 주문한다. + orderNum = self.requestOrder(OrderType.buy, stock_code, buy_count, bs_buy_price) + self.orderChecker.buy(today, "A" + stock_code, buy_count, bs_buy_price, orderNum) + + # slackbot에 메시지를 보냄 + self.slackBot.post_to_slack(stock_code, stock_code, "BUY", bsLine['buy'][len(bsLine['buy']) - 1], buy_count) + + # 로그 출력 + print("BUY", THIS_TIME.strftime('%Y%m%d %H%M%S'), orderNum, stock_code, bs_buy_price, buy_count) + + if bs_sell_price > 1000: + check = self.sellStocks(stock_code, bs_sell_price) + + if check: + # slackbot에 메시지를 보냄 + self.slackBot.post_to_slack(stock_code, stock_code, "SELL", bs_sell_price, 'ALL') + + # 로그 출력 + print("SELL", THIS_TIME.strftime('%Y%m%d %H%M%S'), stock_code, stock_code, bs_sell_price) + + # 로그 출력 + print("TIMECHECK: %s, code: %s, buy: %d, sell: %d, avg5: %.2f, avg30: %.2f, open: %d, high: %d, low: %d, slow_k: %.2f" % + (str(THIS_TIME), stock_code, 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])) + + time.sleep(60) + THIS_TIME = datetime.now() + + return True + + def updteTodayStock(self, stock_code, today_str): + bsLine, data = self.labelChecker.makeCandidate(stock_code, today_str) + self.labelChecker.updateLabel(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" + + hts = HTS_etf(RESOURCE_PATH) + hts.connect2DB("hts.db") + hts.connect2StockDB() + + today_str = today.strftime('%Y%m%d') + hts.buyRealTime(today_str, stock_code, analyzed_day=1000) + + db_filename = os.path.join(RESOURCE_PATH, "hts.db") + hts.insertStockData(stock_code, today) + + hts.disconnectStockDB() + hts.disconnect() + print("done...") \ No newline at end of file diff --git a/HTS_etf_252670.py b/HTS_etf_252670.py new file mode 100644 index 0000000..5177b4e --- /dev/null +++ b/HTS_etf_252670.py @@ -0,0 +1,224 @@ +import time +import os +import math +import sqlite3 +from datetime import datetime, timedelta + +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 +from stock.util.SlackBot import SlackBot +from stock.analysis.StockStatus import StockStatus + + +class HTS_etf(HTS): + RESOURCE_PATH = None + stock_code = None + buy_count = None + orderChecker = None + buySellChecker = None + labelChecker = None + slackBot = None + stockStatus = None + + def __init__(self, RESOURCE_PATH): + super().__init__(RESOURCE_PATH) + + self.RESOURCE_PATH = RESOURCE_PATH + + self.orderChecker = OrderChecker(self.RESOURCE_PATH, "ETF") + self.buySellChecker = BuySellChecker() + self.labelChecker = LabelChecker(RESOURCE_PATH) + self.slackBot = SlackBot() + self.stockStatus = StockStatus(RESOURCE_PATH) + + return + + def connect2StockDB(self): + + self.conn_stock = sqlite3.connect(os.path.join(self.RESOURCE_PATH, "resources/stock.db")) + self.cursor_stock = self.conn_stock.cursor() + + return + + def disconnectStockDB(self): + + self.cursor_stock.close() + self.conn_stock.close() + return + + def sellStocks(self, stock_code=None, bs_sell_price=None): + check = False + jangoDic = self.requstJango() + if jangoDic and len(jangoDic.keys()) > 0: + for code in jangoDic: + if stock_code is not None: + if code == "A" + stock_code and bs_sell_price is not None: + if jangoDic[code]['매도가능'] > 0: + if 2 < jangoDic[code]['평가손익']: + # 2% 이상 시 수익 매도 + self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], bs_sell_price) + self.slackBot.post_to_slack(code, jangoDic[code]['종목명'], "SELL", bs_sell_price, jangoDic[code]['매도가능']) + check = True + else: + continue + else: + if jangoDic[code]['매도가능'] > 0: + if 2 < jangoDic[code]['평가손익']: + # 2% 이상 시 수익 매도 + currentStock = self.currentStock(code[1:]) + self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], currentStock['close']) + self.slackBot.post_to_slack(code, jangoDic[code]['종목명'], "SELL", currentStock['close'], jangoDic[code]['매도가능']) + check = True + return check + + 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이면 장부가로 팔겠다는 의미임 + orderNum = None + jangoDic = self.requstJango() + if jangoDic and len(jangoDic.keys()) > 0: + for code in jangoDic: + if jangoDic[code]['매도가능'] > 0: + if without_loss: + if jangoDic[code]['장부가'] * 0.07 < jangoDic[code]['장부가'] - final_price: + sell_price = jangoDic[code]['장부가'] + if code == "A" + stock_code: + orderNum = self.requestOrder(OrderType.sell, stock_code, jangoDic[code]['매도가능'], sell_price) + return orderNum, 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) + return orderNum, log_time.strftime('%Y%m%d %H%M%S'), jangoDic[code]['매도가능'], sell_price + return orderNum, None, None, None + + def makeTickData(self, data, mins=30): + result = {"check": set(), + "time": [], + "open": [], + "close": [], + "high": [], + "low": [], + "vol": [], + "label": []} + + for i in range(mins, len(data['time']) + 1): + result["check"].add(data['time'][i - 1]) + result["time"].append(data['time'][i - 1]) + + result["open"].append(data['open'][i - mins]) + result["close"].append(data['close'][i - 1]) + result["high"].append(max(data['high'][i - mins: i])) + result["low"].append(min(data['low'][i - mins: i])) + result["vol"].append(sum(data['vol'][i - mins: i])) + + return result + + def buyRealTime(self, today, stock_code, analyzed_day=1000): + MAX_PRICE = 10000 + + print("START...") + THIS_TIME = datetime.now() + + LAST_DATA = self.getLastData(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'): + + # 매도를 체크한다. + self.sellStocks() + + time.sleep(0.1) + + try: + # 데이터를 가지고 온다. + result = self.getRealTime(stock_code, today, LAST_DATA) + except: + print("#ERROR:", stock_code) + continue + + data = self.buySellChecker.analyze(result) + data.drop(data.index[:len(data) - analyzed_day], inplace=True) + + # 사야 할 시점과 팔아야 할 시점을 체크한다. + bsLine = self.buySellChecker.checkTransaction(stock_code, data, None, None, isRealTime=True) + bs_buy_price = bsLine['buy'][0] + bs_buy_weight = bsLine['buy_weight'][0] + bs_sell_price = bsLine['sell'][0] + + # 미체결 기록을 가져와서 10분 이상 된 매수 주문을 취소 한다. + ORDER_LIST = self.requestOrderList() + orderListToCancel = self.orderChecker.cancel(today, "A" + stock_code, ORDER_LIST, mins=10) + if len(orderListToCancel) > 0: + self.cancelOrderList(orderListToCancel) + + if bs_buy_price > 1000: + + if not self.orderChecker.exist(today, "A" + stock_code, hours=9): + buy_count = int(MAX_PRICE / bs_buy_price) + + if buy_count > 0: + # 매수를 주문한다. + orderNum = self.requestOrder(OrderType.buy, stock_code, buy_count, bs_buy_price) + self.orderChecker.buy(today, "A" + stock_code, buy_count, bs_buy_price, orderNum) + + # slackbot에 메시지를 보냄 + self.slackBot.post_to_slack(stock_code, stock_code, "BUY", bsLine['buy'][len(bsLine['buy']) - 1], buy_count) + + # 로그 출력 + print("BUY", THIS_TIME.strftime('%Y%m%d %H%M%S'), orderNum, stock_code, bs_buy_price, buy_count) + + if bs_sell_price > 1000: + check = self.sellStocks(stock_code, bs_sell_price) + + if check: + # slackbot에 메시지를 보냄 + self.slackBot.post_to_slack(stock_code, stock_code, "SELL", bs_sell_price, 'ALL') + + # 로그 출력 + print("SELL", THIS_TIME.strftime('%Y%m%d %H%M%S'), stock_code, stock_code, bs_sell_price) + + # 로그 출력 + print("TIMECHECK: %s, code: %s, buy: %d, sell: %d, avg5: %.2f, avg30: %.2f, open: %d, high: %d, low: %d, slow_k: %.2f" % + (str(THIS_TIME), stock_code, 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])) + + time.sleep(60) + THIS_TIME = datetime.now() + + return True + + def updteTodayStock(self, stock_code, today_str): + bsLine, data = self.labelChecker.makeCandidate(stock_code, today_str) + self.labelChecker.updateLabel(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" + + hts = HTS_etf(RESOURCE_PATH) + hts.connect2DB("hts.db") + hts.connect2StockDB() + + today_str = today.strftime('%Y%m%d') + hts.buyRealTime(today_str, stock_code, analyzed_day=1000) + + db_filename = os.path.join(RESOURCE_PATH, "hts.db") + hts.insertStockData(stock_code, today) + + hts.disconnectStockDB() + hts.disconnect() + print("done...") \ No newline at end of file diff --git a/hts/BuySellChecker.py b/hts/BuySellChecker.py index 1b3f5de..68ded1a 100644 --- a/hts/BuySellChecker.py +++ b/hts/BuySellChecker.py @@ -352,23 +352,32 @@ class BuySellChecker: else: buy, buy_weight = self.getBuyPriceAndWeight_122630(last_index, data) sell, sell_weight = self.getSellPriceAndWeight(last_index, data) + if data.index[last_index].strftime('%H:%M:%S') > datetime.strptime(datetime.today().strftime("%Y-%m-%d 15:10:00"), "%Y-%m-%d %H:%M:%S").strftime('%H:%M:%S'): + buy, buy_weight = -1, -1 - if sell > 0 and 'last_buy' in bsLine[stock_code]: - if bsLine[stock_code]['last'] == 'buy': - if sell - bsLine[stock_code]['last_buy'] < 0.007: - sell, weight = -1, -1 + if sell > 0: + if 'last_buy' in bsLine[stock_code]: + if bsLine[stock_code]['last'] == 'buy': + if sell - bsLine[stock_code]['last_buy'] < 0.007: + sell, weight = -1, -1 + else: + sell, weight = -1, -1 if 'last' in bsLine[stock_code] and bsLine[stock_code]['last'] != 'buy': sell, weight = -1, -1 - bsLine[stock_code]['buy'] = [buy] - bsLine[stock_code]['buy_weight'] = [buy_weight] - bsLine[stock_code]['sell'] = [sell] - bsLine[stock_code]['sell_weight'] = [sell_weight] + bsLine[stock_code]['buy'][last_index] = buy + bsLine[stock_code]['buy_weight'][last_index] = buy_weight + bsLine[stock_code]['sell'][last_index] = sell + bsLine[stock_code]['sell_weight'][last_index] = sell_weight + if buy > 0: bsLine[stock_code]['last'] = 'buy' bsLine[stock_code]['last_buy'] = buy + bsLine[stock_code]['buy_count'] += 1 if sell > 0: bsLine[stock_code]['last'] = 'sell' + bsLine[stock_code]['last_buy'] = -1 + bsLine[stock_code]['buy_count'] = 0 else: # Type=False, 시뮬레이션 적용 @@ -399,11 +408,6 @@ class BuySellChecker: sell, weight = -1, -1 if 'last' in bsLine[stock_code] and bsLine[stock_code]['last'] != 'buy': sell, weight = -1, -1 - #if data.index[last_index].strftime('%H:%M:%S') > datetime.strptime(datetime.today().strftime("%Y-%m-%d 15:10:00"), "%Y-%m-%d %H:%M:%S").strftime('%H:%M:%S'): - # if 'last' in bsLine[stock_code] and bsLine[stock_code]['last'] == 'buy': - # sell, weight = data['close'][last_index], -1 - # bsLine[stock_code]['last'] = '' - # bsLine[stock_code]['last_buy'] = -1 bsLine[stock_code]['buy'][last_index] = buy bsLine[stock_code]['buy_weight'][last_index] = buy_weight diff --git a/hts/HTS.py b/hts/HTS.py index c209222..9e8fce9 100644 --- a/hts/HTS.py +++ b/hts/HTS.py @@ -463,7 +463,7 @@ class HTS: return data - def insertStockData(self, stocks, this_day): + def insertStockData(self, stock_code, this_day): # 테이블 생성 self.cursor.execute("CREATE TABLE IF NOT EXISTS hts (CODE text, NAME text, ymd text, hms text, close REAL, open REAL, high REAL, low REAL, volume REAL, label INTEGER DEFAULT 0)") @@ -472,23 +472,21 @@ class HTS: create_key = "CREATE INDEX IF NOT EXISTS hts_idx on hts(CODE, ymd, hms) " self.cursor.execute(create_key) - for stock in stocks: + items = self.getStockInfo(stock_code, this_day.strftime('%Y%m%d')) - items = self.getStockInfo(stock["stock_code"], this_day.strftime('%Y%m%d')) + 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] - 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] + self.cursor.execute('DELETE FROM hts WHERE CODE=? and ymd=? and hms=?', (stock["stock_code"], ymd, hms,)) + self.cursor.execute("INSERT INTO hts (CODE, NAME, ymd, hms, close, open, high, low, volume) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)", (stock["stock_code"], stock["stock_name"], ymd, hms, close, open, high, low, volume)) - self.cursor.execute('DELETE FROM hts WHERE CODE=? and ymd=? and hms=?', (stock["stock_code"], ymd, hms,)) - self.cursor.execute("INSERT INTO hts (CODE, NAME, ymd, hms, close, open, high, low, volume) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)", (stock["stock_code"], stock["stock_name"], ymd, hms, close, open, high, low, volume)) - - self.conn.commit() + self.conn.commit() return @@ -793,6 +791,7 @@ class HTS: "disparity_avg20": -1, "disparity_avg60": -1, "disparity_avg120": -1, + "disparity_avg200": -1, "bolingerband_upper": -1, "bolingerband_lower": -1, "bolingerband_middle": -1,