From 2f130a8dbeb27c6c487a5907cc682ba251bfbcda Mon Sep 17 00:00:00 2001 From: dsyoon Date: Mon, 16 Oct 2023 11:32:19 +0900 Subject: [PATCH] init --- HTS_etf_251340.py | 211 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 HTS_etf_251340.py diff --git a/HTS_etf_251340.py b/HTS_etf_251340.py new file mode 100644 index 0000000..30a84c0 --- /dev/null +++ b/HTS_etf_251340.py @@ -0,0 +1,211 @@ +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 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: + if bs_sell_price is not None: + if jangoDic[code]['매도가능'] > 0: + if jangoDic[code]['평가손익'] < -1.5 or 3 < jangoDic[code]['평가손익']: + # 1.5% 손해 혹은 2% 이상 시 수익 매도 + self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], bs_sell_price) + check = True + else: + if jangoDic[code]['매도가능'] > 0: + if jangoDic[code]['평가손익'] < -1.5 or 3 < jangoDic[code]['평가손익']: + # 1.5% 손해 혹은 2% 이상 시 수익 매도 + self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], jangoDic[code]['현재가']) + check = True + else: + if jangoDic[code]['매도가능'] > 0: + if jangoDic[code]['평가손익'] < -1.5 or 3 < jangoDic[code]['평가손익']: + # 1.5% 손해 혹은 2% 이상 시 수익 매도 + self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], 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, stock_name, analyzed_day=1000): + MAX_PRICE = 100000 + + print("START...") + THIS_TIME = datetime.now() + + LAST_DATA = self.getLastData(stock_code, today) + + while datetime.strptime(today + " 063000", '%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(stock_code) + + 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=30) + 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) + + # 로그 출력 + 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: + + # 로그 출력 + 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])) + + if int(THIS_TIME.strftime("%M")) % 10 == 0: + self.slackBot.post_live_to_slack(stock_code, stock_name) + + 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 = "251340" + stock_name = "KODEX 코스닥150선물인버스" + + hts = HTS_etf(RESOURCE_PATH) + hts.connect2DB("hts.db") + + today_str = today.strftime('%Y%m%d') + hts.buyRealTime(today_str, stock_code, stock_name, analyzed_day=1000) + + db_filename = os.path.join(RESOURCE_PATH, "hts.db") + hts.insertStockData(today, stock_code, stock_name) + + hts.disconnect() + print("done...") \ No newline at end of file