From fbfab6d2366b3bfed9accb02fb8680b993d25c06 Mon Sep 17 00:00:00 2001 From: dsyoon Date: Tue, 12 Dec 2023 00:15:38 +0900 Subject: [PATCH] init --- HTS_etf.py | 382 +++++++++++++++++++++++------- HTS_etf_122630.py | 6 +- HTS_etf_233740.py | 6 +- HTS_etf_251340.py | 6 +- HTS_etf_252670.py | 6 +- hts/BuySellChecker.py | 477 ++++++++++++++++++-------------------- stock/util/TelegramBot.py | 26 ++- 7 files changed, 550 insertions(+), 359 deletions(-) diff --git a/HTS_etf.py b/HTS_etf.py index 41efa23..f48939f 100644 --- a/HTS_etf.py +++ b/HTS_etf.py @@ -1,6 +1,5 @@ import time -import os -import sqlite3 +import pandas as pd from datetime import datetime from hts.HTS import HTS @@ -11,11 +10,14 @@ from stock.util.LabelChecker import LabelChecker from stock.util.TelegramBot import TelegramBot from stock.analysis.StockStatus import StockStatus -from hts.BuySellChecker_122630 import BuySellChecker_122630 -from hts.BuySellChecker_233740 import BuySellChecker_233740 -from hts.BuySellChecker_251340 import BuySellChecker_251340 -from hts.BuySellChecker_252670 import BuySellChecker_252670 +from stock.analysis.Common import Common +from stock.analysis.Stochastic import Stochastic +from stock.analysis.RSI import RSI +from stock.analysis.MACD import MACD +from stock.analysis.IchimokuCloud import IchimokuCloud +from statsmodels.tsa.seasonal import seasonal_decompose +from hts.BuySellChecker import BuySellChecker class HTS_etf(HTS): RESOURCE_PATH = None @@ -25,10 +27,16 @@ class HTS_etf(HTS): buy_count = None orderChecker = None buySellChecker = None - labelChecker = None bot = None stockStatus = None + common = None + stochastic = None + rsi = None + macd = None + ichimokuCloud = None + + def __init__(self, RESOURCE_PATH, stock_code, stock_name, SELL_GAP): super().__init__(RESOURCE_PATH) @@ -42,19 +50,19 @@ class HTS_etf(HTS): self.bot = TelegramBot() self.stockStatus = StockStatus(RESOURCE_PATH) - self.buySellChecker = None - if stock_code == '122630': - self.buySellChecker = BuySellChecker_122630() - elif stock_code == '233740': - self.buySellChecker = BuySellChecker_233740() - elif stock_code == '251340': - self.buySellChecker = BuySellChecker_251340() - elif stock_code == '252670': - self.buySellChecker = BuySellChecker_252670() + self.common = Common() + self.stochastic = Stochastic() + self.rsi = RSI() + self.macd = MACD() + self.ichimokuCloud = IchimokuCloud() + self.buySellChecker = BuySellChecker() return + def getBallance(self): + return + def sellStocks(self, stock_code=None, bs_sell_price=None): check = False jangoDic = self.requstJango() @@ -64,19 +72,19 @@ class HTS_etf(HTS): 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]['평가손익'] or self.SELL_GAP < jangoDic[code]['평가금액']-jangoDic[code]['매입금액']: + if jangoDic[code]['평가손익'] < -1.0 or 2 < jangoDic[code]['평가손익'] or self.SELL_GAP < jangoDic[code]['평가금액']-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]['평가손익'] or self.SELL_GAP < jangoDic[code]['평가금액']-jangoDic[code]['매입금액']: + if jangoDic[code]['평가손익'] < -1.0 or 2 < jangoDic[code]['평가손익'] or self.SELL_GAP < jangoDic[code]['평가금액']-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]['평가손익'] or self.SELL_GAP < jangoDic[code]['평가금액']-jangoDic[code]['매입금액']: + if jangoDic[code]['평가손익'] < -1.0 or 2 < jangoDic[code]['평가손익'] or self.SELL_GAP < jangoDic[code]['평가금액']-jangoDic[code]['매입금액']: # 1.5% 손해 혹은 2% 이상 시 수익 매도 self.requestOrder(OrderType.sell, code[1:], jangoDic[code]['매도가능'], jangoDic[code]['현재가']) check = True @@ -105,6 +113,188 @@ class HTS_etf(HTS): return orderNum, log_time.strftime('%Y%m%d %H%M%S'), jangoDic[code]['매도가능'], sell_price return orderNum, None, None, None + def analyze(self, result): + # 기본 캔들 정보 + open = result["open"] + close = result["close"] + high = result["high"] + low = result["low"] + volume = result["vol"] + + if "volume_down" in result: + volume_down = result["volume_down"] + if "volume_up" in result: + volume_up = result["volume_up"] + if "volume_updown_diff" in result: + volume_updown_diff = result["volume_updown_diff"] + + # 이동 평균 + close_df = pd.DataFrame(close) + avg5_list = close_df.rolling(window=5).mean().fillna(close[0]).values.tolist() + avg5 = [item[0] for item in avg5_list] + avg20_list = close_df.rolling(window=20).mean().fillna(close[0]).values.tolist() + avg20 = [item[0] for item in avg20_list] + avg30_list = close_df.rolling(window=30).mean().fillna(close[0]).values.tolist() + avg30 = [item[0] for item in avg30_list] + avg60_list = close_df.rolling(window=60).mean().fillna(close[0]).values.tolist() + avg60 = [item[0] for item in avg60_list] + avg120_list = close_df.rolling(window=120).mean().fillna(close[0]).values.tolist() + avg120 = [item[0] for item in avg120_list] + avg240_list = close_df.rolling(window=240).mean().fillna(close[0]).values.tolist() + avg240 = [item[0] for item in avg240_list] + avg480_list = close_df.rolling(window=480).mean().fillna(close[0]).values.tolist() + avg480 = [item[0] for item in avg480_list] + avg1500_list = close_df.rolling(window=1500).mean().fillna(close[0]).values.tolist() + avg1500 = [item[0] for item in avg1500_list] + + size = int(len(close) / 8) + pos = round(size / 2) + close_temp = close + [close[-1]] * pos + decomposition_results = seasonal_decompose(close_temp, model='multiplicative', period=size) + trend = decomposition_results.trend[:-pos] + trend_df = pd.DataFrame(trend).fillna(close[0]) + trend_avg_list = trend_df.rolling(window=20).mean().values.tolist() + trend_avg = [item[0] for item in trend_avg_list] + + open_df = pd.DataFrame(close) + disparity_avg5_list = (open_df / close_df.rolling(window=5).mean()).values.tolist() + disparity_avg5 = [item[0] for item in disparity_avg5_list] + disparity_avg20_list = (open_df / close_df.rolling(window=20).mean()).values.tolist() + disparity_avg20 = [item[0] for item in disparity_avg20_list] + disparity_avg30_list = (open_df / close_df.rolling(window=30).mean()).values.tolist() + disparity_avg30 = [item[0] for item in disparity_avg30_list] + disparity_avg60_list = (open_df / close_df.rolling(window=60).mean()).values.tolist() + disparity_avg60 = [item[0] for item in disparity_avg60_list] + disparity_avg120_list = (open_df / close_df.rolling(window=120).mean()).values.tolist() + disparity_avg120 = [item[0] for item in disparity_avg120_list] + disparity_avg240_list = (open_df / close_df.rolling(window=240).mean()).values.tolist() + disparity_avg240 = [item[0] for item in disparity_avg240_list] + disparity_avg480_list = (open_df / close_df.rolling(window=480).mean()).values.tolist() + disparity_avg480 = [item[0] for item in disparity_avg480_list] + disparity_avg1500_list = (open_df / close_df.rolling(window=1500).mean()).values.tolist() + disparity_avg1500 = [item[0] for item in disparity_avg1500_list] + + # 볼린져 밴드 + df = pd.DataFrame(close) + max20 = df.rolling(window=20).mean() + stddev20 = df.rolling(window=20).std() + upper_df = max20 + (stddev20 * 2) # 상단 볼린저 밴드 + lower_df = max20 - (stddev20 * 2) # 하단 볼린저 밴드 + middle_df = (upper_df + lower_df) / 2 + upper_limit_df = upper_df - (upper_df - lower_df) * 0.1 + lower_limit_df = (upper_df - lower_df) * 0.15 + lower_df + + upper, lower, middle, upper_limit, lower_limit = [], [], [], [], [] + for i in range(len(upper_df)): + if i < 10: + upper.append(upper_df.values[0][0]) + lower.append(lower_df.values[0][0]) + middle.append(middle_df.values[0][0]) + upper_limit.append(upper_limit_df.values[0][0]) + lower_limit.append(lower_limit_df.values[0][0]) + else: + upper.append(upper_df.values[i][0]) + lower.append(lower_df.values[i][0]) + middle.append(middle_df.values[i][0]) + upper_limit.append(upper_limit_df.values[i][0]) + lower_limit.append(lower_limit_df.values[i][0]) + + upper, lower = [], [] + for i in range(len(upper_df)): + if i < 10: + upper.append(upper_df.values[0][0]) + lower.append(lower_df.values[0][0]) + else: + upper.append(upper_df.values[i][0]) + lower.append(lower_df.values[i][0]) + + point_temp = result["time"] + STOCK = [] + if "volume_up" in result and "volume_updown_diff" in result: + for i in range(len(open)): + STOCK.append({'volume': volume[i], 'volume_down': volume_down[i], 'volume_up': volume_up[i], 'volume_updown_diff': volume_updown_diff[i], 'close': close[i], 'open': open[i], 'high': high[i], 'low': low[i], + 'avg5': avg5[i], 'avg20': avg20[i], 'avg60': avg60[i], 'avg120': avg120[i], 'avg240': avg240[i], 'avg480': avg480[i], 'avg1500': avg1500[i]}) + else: + for i in range(len(open)): + STOCK.append({'volume': volume[i], 'close': close[i], 'open': open[i], 'high': high[i], 'low': low[i], + 'avg5': avg5[i], 'avg20': avg20[i], 'avg60': avg60[i], 'avg120': avg120[i], 'avg240': avg240[i], 'avg480': avg480[i], 'avg1500': avg1500[i]}) + + # stochastic + stochastic_df = self.stochastic.apply(STOCK, n=30, m=5, t=5) + fast_k = stochastic_df['fast_k'].values.tolist() + slow_k = stochastic_df['slow_k'].values.tolist() + slow_d = stochastic_df['slow_d'].values.tolist() + + # macd + #macd_df = self.macd.apply(STOCK, short=12, long=26, t=9) + macd_df = self.macd.apply(STOCK, short=5, long=20, t=5) + macd = macd_df['macd'].values.tolist() + macds = macd_df['macds'].values.tolist() + macdo = macd_df['macdo'].values.tolist() + + # rsi + rsi_df = self.rsi.apply(STOCK, period=30, window=5) + rsi = rsi_df['rsi'].values.tolist() + rsis = rsi_df['rsis'].values.tolist() + + # ichimokuCloud + ichimokuCloud_df = self.ichimokuCloud.apply(STOCK, c=9, b=26, l=52) + ichimokuCloud_df = ichimokuCloud_df[:len(ichimokuCloud_df) - 51] + changeLine = ichimokuCloud_df['changeLine'].values.tolist() + baseLine = ichimokuCloud_df['baseLine'].values.tolist() + laggingSpan = ichimokuCloud_df['laggingSpan'].values.tolist() + leadingSpan1 = ichimokuCloud_df['leadingSpan1'].values.tolist() + leadingSpan2 = ichimokuCloud_df['leadingSpan2'].values.tolist() + + # 결과 + if "volume_up" in result and "volume_updown_diff" in result: + temp = { + "ymd": point_temp, + "open": open, "high": high, "low": low, "close": close, "volume": volume, "volume_down": volume_down, + "volume_up": volume_up, "volume_updown_diff": volume_updown_diff, + "trend": trend, "trend_avg": trend_avg, + "avg5": avg5, "avg20": avg20, "avg60": avg60, "avg120": avg120, "avg240": avg240, "avg480": avg480, + "avg1500": avg1500, + "disparity_avg5": disparity_avg5, "disparity_avg20": disparity_avg20, + "disparity_avg30": disparity_avg30, "disparity_avg60": disparity_avg60, + "disparity_avg120": disparity_avg120, "disparity_avg240": disparity_avg240, + "disparity_avg480": disparity_avg480, "disparity_avg1500": disparity_avg1500, + "upper": upper, "lower": lower, 'middle': middle, 'upper_limit': upper_limit, + 'lower_limit': lower_limit, + "macd": macd, "macds": macds, "macdo": macdo, + "fast_k": fast_k, "slow_k": slow_k, "slow_d": slow_d, + "rsi": rsi, "rsis": rsis, + "changeLine": changeLine, "baseLine": baseLine, "laggingSpan": laggingSpan, + "leadingSpan1": leadingSpan1, "leadingSpan2": leadingSpan2, + } + else: + temp = { + "ymd": point_temp, + "open": open, "high": high, "low": low, "close": close, "volume": volume, + "trend": trend, "trend_avg": trend_avg, + "avg5": avg5, "avg20": avg20, "avg60": avg60, "avg120": avg120, "avg240": avg240, "avg480": avg480, + "avg1500": avg1500, + "disparity_avg5": disparity_avg5, "disparity_avg20": disparity_avg20, + "disparity_avg30": disparity_avg30, "disparity_avg60": disparity_avg60, + "disparity_avg120": disparity_avg120, "disparity_avg240": disparity_avg240, + "disparity_avg480": disparity_avg480, "disparity_avg1500": disparity_avg1500, + "upper": upper, "lower": lower, 'middle': middle, 'upper_limit': upper_limit, + 'lower_limit': lower_limit, + "macd": macd, "macds": macds, "macdo": macdo, + "fast_k": fast_k, "slow_k": slow_k, "slow_d": slow_d, + "rsi": rsi, "rsis": rsis, + "changeLine": changeLine, "baseLine": baseLine, "laggingSpan": laggingSpan, + "leadingSpan1": leadingSpan1, "leadingSpan2": leadingSpan2, + } + + data = pd.DataFrame(temp) + df_final_time = pd.DatetimeIndex(point_temp) + data.index = df_final_time + + data = data.fillna(-1) + return data + + def makeTickData(self, data, mins=30): result = {"check": set(), "time": [], @@ -127,30 +317,63 @@ class HTS_etf(HTS): return result + def makeTickData1(self, data, mins=5): + result = { + "ymd": [], + "open": [], "close": [], "high": [], "low": [], "volume": [], "volume_up": [], "volume_down": [], "volume_updown_diff": [] + } - def getLIMITInfo(self, stock_code, ymd, dbfile_name="stock.db"): - conn = sqlite3.connect(os.path.join(self.RESOURCE_PATH, dbfile_name)) - cursor = conn.cursor() + for i in range(mins, len(data['ymd'])+1): + result["ymd"].append(data['ymd'][i-1]) - cursor.execute('select ymd, open, close, high, low, volume from stock where code=? order by ymd desc limit ?', - (stock_code, 100,)) - db_result = cursor.fetchall() - cursor.close() - conn.close() + result["open"].append(data['open'][i-mins]) + result["close"].append(data['close'][i-1]) - match = False - LIMIT_PRICE = [] - for i, rows in enumerate(db_result): - if rows[0].replace('.', '') == ymd: - match = True - if match: - LIMIT_PRICE.append(rows[2]) + result["high"].append(max(data['high'][i - mins: i])) + result["low"].append(min(data['low'][i - mins: i])) + result["volume"].append(sum(data['volume'][i - mins: i])) - return {'LOW_PRICE': sum(LIMIT_PRICE[:20]) / len(LIMIT_PRICE[:20])} + up = [data['volume'][i - mins + c] for c in range(len(data['volume'][i - mins: i])) if data['open'][i - mins + c] < data['close'][i - mins + c]] + down = [data['volume'][i - mins + c] for c in range(len(data['volume'][i - mins: i])) if data['close'][i - mins + c] < data['open'][i - mins + c]] + result["volume_up"].append(sum(up)) + result["volume_down"].append(sum(down)) + result["volume_updown_diff"].append(sum(up) - sum(down)) + return result - def buyRealTime(self, today, analyzed_day=1000, logFp=None, MAX_PRICE=30000): - INFO = self.getLIMITInfo(self.stock_code, today) + def makeTickData2(self, data, mins=5): + result = { + "ymd": [], + "open": [], "close": [], "high": [], "low": [], "volume": [], "volume_up": [], "volume_down": [], "volume_updown_diff": [] + } + + for i in range(mins, len(data['ymd'])+1, mins): + result["ymd"].append(data['ymd'][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["volume"].append(data['volume'][i-1]) + if data['open'][i-1] < data['close'][i-1]: + result["volume_up"].append(data['volume'][i-1]) + result["volume_down"].append(0) + elif data['close'][i-1] < data['open'][i-1]: + result["volume_down"].append(-1*data['volume'][i-1]) + result["volume_up"].append(0) + else: + result["volume_up"].append(0) + result["volume_down"].append(0) + + up = [data['volume'][i - mins + c] for c in range(len(data['volume'][i - mins: i])) if data['close'][i - mins + c] < data['open'][i - mins + c]] + down = [data['volume'][i - mins + c] for c in range(len(data['volume'][i - mins: i])) if data['close'][i - mins + c] < data['open'][i - mins + c]] + result["volume_updown_diff"].append(sum(up) - sum(down)) + + return result + + def buyRealTime(self, today, MAX_PRICE=30000): + BUY_LIST = {'buy_count': 0, 'buy_avg': 0, 'buy_list': []} print("START...") THIS_TIME = datetime.now() @@ -160,69 +383,72 @@ class HTS_etf(HTS): 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 + " 090100", '%Y%m%d %H%M%S'): self.bot.sendMsg("START... {} ({}) SLOW_K: {}".format(self.stock_code, self.stock_name, MAX_PRICE)) - logFp.write("START {} ({}) SLOW_K: {}\n".format(self.stock_code, self.stock_name, MAX_PRICE)) 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(self.stock_code) + check = self.sellStocks(self.stock_code) + + buy_avg = self.getBallance(self.stock_code) + if check or buy_avg == 0: + BUY_LIST['buy_avg'] = 0 + BUY_LIST['buy_count'] = 0 + BUY_LIST['buy_list'].clear() time.sleep(0.1) try: # 데이터를 가지고 온다. - result = self.getRealTime(self.stock_code, today, LAST_DATA) + result_m1 = self.getRealTime(self.stock_code, today, LAST_DATA) except: print("#ERROR:", self.stock_code) continue - data = self.buySellChecker.analyze(result) - data.drop(data.index[:len(data) - analyzed_day], inplace=True) + result_tic_m1 = self.makeTickData1(result_m1, mins=1) + data = self.buySellChecker.analyze(result_tic_m1) + result_tic_m30 = self.makeTickData2(result_tic_m1, mins=30) + data_signal = self.buySellChecker.analyze(result_tic_m30) + + #data.drop(data.index[:len(data) - analyzed_day], inplace=True) # 사야 할 시점과 팔아야 할 시점을 체크한다. - bsLine = self.buySellChecker.checkTransaction(self.stock_code, data, INFO, isRealTime=True) - bs_buy_price = bsLine['buy'][0] - bs_buy_weight = bsLine['buy_weight'][0] - bs_sell_price = bsLine['sell'][0] + bsLine1 = self.buySellChecker.checkTransaction1(self.stock_code, MAX_PRICE, data, data_signal, BUY_LIST, isRealTime=True) + + if 'sell_price' in bsLine1: + sell_price = bsLine1['sell_price'][-1] + if 0 < sell_price: + profit_rate = 1.002 + if buy_avg * profit_rate < data['close'][-1]: + check = self.sellStocks(self.stock_code, sell_price) + if check: + self.orderChecker.sell(datetime.today().strftime('%Y%m%d'), self.stock_code) + BUY_LIST['buy_avg'] = 0 + BUY_LIST['buy_count'] = 0 + BUY_LIST['buy_list'].clear() + self.bot.sendMsg( "Profit {:.2f}, {} ({})".format(amount * (profit_rate - 1), self.stock_code, self.stock_name)) + + if 'buy_price' in bsLine1: + buy_price = bsLine1['buy_price'][-1] + buy_count = bsLine1['buy_count'][-1] + if buy_price > 0: + # 매수를 요청 한다. + amount = buy_price * buy_count + orderNum = self.requestOrder(OrderType.buy, self.stock_code, buy_count, buy_price) + self.orderChecker.buy(today, "A" + self.stock_code, buy_count, buy_price, orderNum) + + self.orderChecker.buy(datetime.today().strftime('%Y%m%d'), self.stock_code, buy_count, buy_price) + self.bot.post(self.stock_code, self.stock_name, "[BUY] ", buy_price, buy_count, data['rsi'][-1], -1) # 미체결 기록을 가져와서 10분 이상 된 매수 주문을 취소 한다. - ORDER_LIST = self.requestOrderList() - orderListToCancel = self.orderChecker.cancel(today, "A" + self.stock_code, ORDER_LIST, mins=10) - if len(orderListToCancel) > 0: - self.cancelOrderList(orderListToCancel) + #ORDER_LIST = self.requestOrderList() + #orderListToCancel = self.orderChecker.cancel(today, "A" + self.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" + self.stock_code, hours=9): - buy_count = int(MAX_PRICE / bs_buy_price) - - if buy_count > 0: - # 매수를 주문한다. - orderNum = self.requestOrder(OrderType.buy, self.stock_code, buy_count, bs_buy_price) - self.orderChecker.buy(today, "A" + self.stock_code, buy_count, bs_buy_price, orderNum) - - # 로그 출력 - print("BUY", THIS_TIME.strftime('%Y%m%d %H%M%S'), orderNum, self.stock_code, bs_buy_price, buy_count) - logFp.write("{} BUY {} {} {}\n".format(THIS_TIME.strftime('%Y%m%d %H%M%S'), self.stock_code, bs_buy_price, buy_count)) - - if bs_sell_price > 1000: - check = self.sellStocks(self.stock_code, bs_sell_price) - - if check: - # 로그 출력 - print("SELL", THIS_TIME.strftime('%Y%m%d %H%M%S'), self.stock_code, self.stock_name, bs_sell_price) - logFp.write("{} SELL {} {} {}\n".format(THIS_TIME.strftime('%Y%m%d %H%M%S'), self.stock_code, bs_buy_price, bs_sell_price)) - - # 로그 출력 - print("TIMECHECK: %s, code: %s, buy: %d, sell: %d, open: %d, close: %d, high: %d, low: %d, macd: %.2f" % - (str(THIS_TIME), self.stock_code, bs_buy_price, bs_sell_price, data["open"][len(data["open"])-1], data["close"][len(data["close"])-1], data["high"][len(data["high"])-1], data["low"][len(data["low"])-1], data["macd"][len(data["macd"])-1])) - logFp.write("TIMECHECK: %s, code: %s, buy: %d, sell: %d, open: %d, close: %d, high: %d, low: %d, macd: %.2f\n" % - (str(THIS_TIME), self.stock_code, bs_buy_price, bs_sell_price, data["open"][len(data["open"])-1], data["close"][len(data["close"])-1], data["high"][len(data["high"])-1], data["low"][len(data["low"])-1], data["macd"][len(data["macd"])-1])) if (int(THIS_TIME.strftime("%M")) % 50 == 0 or int(THIS_TIME.strftime("%M")) % 20 == 0): self.bot.alarm_live(self.stock_code, self.stock_name, data["close"][len(data["close"])-1], data["macd"][len(data["macd"])-1]) - logFp.flush() time.sleep(60) THIS_TIME = datetime.now() diff --git a/HTS_etf_122630.py b/HTS_etf_122630.py index ba5f395..cd5fb72 100644 --- a/HTS_etf_122630.py +++ b/HTS_etf_122630.py @@ -19,11 +19,9 @@ if __name__ == "__main__": if not os.path.exists(os.path.join(RESOURCE_PATH, "log")): os.mkdir(os.path.join(RESOURCE_PATH, "log")) - logFp = open(os.path.join(RESOURCE_PATH, "log", today_str + "_" + stock_code + ".log"), "w", encoding='utf-8') - MAX_PRICE = 30000 - hts.buyRealTime(today_str, analyzed_day=1000, logFp=logFp, MAX_PRICE=MAX_PRICE) - logFp.close() + MAX_PRICE = 300000 + hts.buyRealTime(today_str, MAX_PRICE=MAX_PRICE) db_filename = os.path.join(RESOURCE_PATH, "hts.db") hts.insertStockData(today, stock_code, stock_name) diff --git a/HTS_etf_233740.py b/HTS_etf_233740.py index 496a7f1..ce3ec4b 100644 --- a/HTS_etf_233740.py +++ b/HTS_etf_233740.py @@ -19,11 +19,9 @@ if __name__ == "__main__": if not os.path.exists(os.path.join(RESOURCE_PATH, "log")): os.mkdir(os.path.join(RESOURCE_PATH, "log")) - logFp = open(os.path.join(RESOURCE_PATH, "log", today_str + "_" + stock_code + ".log"), "w", encoding='utf-8') - MAX_PRICE = 30000 - hts.buyRealTime(today_str, analyzed_day=1000, logFp=logFp, MAX_PRICE=MAX_PRICE) - logFp.close() + MAX_PRICE = 300000 + hts.buyRealTime(today_str, MAX_PRICE=MAX_PRICE) db_filename = os.path.join(RESOURCE_PATH, "hts.db") hts.insertStockData(today, stock_code, stock_name) diff --git a/HTS_etf_251340.py b/HTS_etf_251340.py index f3e969b..3dec427 100644 --- a/HTS_etf_251340.py +++ b/HTS_etf_251340.py @@ -19,11 +19,9 @@ if __name__ == "__main__": if not os.path.exists(os.path.join(RESOURCE_PATH, "log")): os.mkdir(os.path.join(RESOURCE_PATH, "log")) - logFp = open(os.path.join(RESOURCE_PATH, "log", today_str + "_" + stock_code + ".log"), "w", encoding='utf-8') - MAX_PRICE = 30000 - hts.buyRealTime(today_str, analyzed_day=1000, logFp=logFp, MAX_PRICE=MAX_PRICE) - logFp.close() + MAX_PRICE = 300000 + hts.buyRealTime(today_str, MAX_PRICE=MAX_PRICE) db_filename = os.path.join(RESOURCE_PATH, "hts.db") hts.insertStockData(today, stock_code, stock_name) diff --git a/HTS_etf_252670.py b/HTS_etf_252670.py index c6f2822..77cdbee 100644 --- a/HTS_etf_252670.py +++ b/HTS_etf_252670.py @@ -19,11 +19,9 @@ if __name__ == "__main__": if not os.path.exists(os.path.join(RESOURCE_PATH, "log")): os.mkdir(os.path.join(RESOURCE_PATH, "log")) - logFp = open(os.path.join(RESOURCE_PATH, "log", today_str + "_" + stock_code + ".log"), "w", encoding='utf-8') - MAX_PRICE = 30000 - hts.buyRealTime(today_str, analyzed_day=1000, logFp=logFp, MAX_PRICE=MAX_PRICE) - logFp.close() + MAX_PRICE = 300000 + hts.buyRealTime(today_str, MAX_PRICE=MAX_PRICE) db_filename = os.path.join(RESOURCE_PATH, "hts.db") hts.insertStockData(today, stock_code, stock_name) diff --git a/hts/BuySellChecker.py b/hts/BuySellChecker.py index ada3f1e..0fc0d32 100644 --- a/hts/BuySellChecker.py +++ b/hts/BuySellChecker.py @@ -1,144 +1,211 @@ -import pandas as pd +import os +from dtw import dtw +import json +import sqlite3 +import numpy as np +from datetime import datetime, timedelta -from stock.analysis.Common import Common -from stock.analysis.Stochastic import Stochastic -from stock.analysis.RSI import RSI -from stock.analysis.MACD import MACD -from stock.analysis.IchimokuCloud import IchimokuCloud +class BuySellChecker(): + PATTERNS = None + RESOURCE_PATH = None -class BuySellChecker: - common = None - stochastic = None - rsi = None - macd = None - ichimokuCloud = None - - BUY_COUNT = None - - def __init__(self): - self.common = Common() - self.stochastic = Stochastic() - self.rsi = RSI() - self.macd = MACD() - self.ichimokuCloud = IchimokuCloud() - - self.BUY_COUNT = 0 - + def __init__(self, RESOURCE_PATH, ticker): + self.RESOURCE_PATH = RESOURCE_PATH + self.readBuyPattern(RESOURCE_PATH, ticker) return - def getBuyPriceAndWeight(self, i, data): - buy, weight, type = -1, -1, "" + def readBuyPattern(self, RESOURCE_PATH, ticker): + with open(os.path.join(RESOURCE_PATH, "buy_pattern_data.json"), 'r') as f: + PATTERNS = json.load(f) - """ - # 매수전략 #1: 다이버전스 - if data['macd'][i] < 0 and data['open'][i] < data['close'][i]: - if 0 < len(data['rsi'].tolist()[i - 10:i - 5]): - if min(data['rsi'].tolist()[i - 10:i - 5]) < data['rsi'][i - 1]: - if data['low'][i - 1] < min(data['low'].tolist()[i - 10:i - 5]): - weight = 1 - buy = data['close'][i] - type = 'Divergence' - """ + self.PATTERNS = {'min_max': [], 'stndardization': []} + for key in PATTERNS: + for min_max in PATTERNS[key]['min_max']: + self.PATTERNS['min_max'].append(min_max) + for stndardization in PATTERNS[key]['stndardization']: + self.PATTERNS['stndardization'].append(stndardization) + return - high_barrier = 70 - low_barrier = 30 - Buy_Price=[] - Sell_Price=[] - number=[] - temp01 = [] - temp01_id = [] - temp02 = [] - temp01_id = [] - temp01_min_price = [] - temp02_min_price = [] - temp01_min_rsi = [] - temp02_min_rsi = [] - n_id=[] - i_id=[] - flag=1 - n = 0 + def nearDisparity(self, data, i): + if (0.998 < data['disparity_avg5'][i] < 1.002 and + 0.998 < data['disparity_avg5'][i] < 1.002 and + 0.998 < data['disparity_avg5'][i] < 1.002 and + 0.998 < data['disparity_avg5'][i] < 1.002 and + 0.998 < data['disparity_avg5'][i] < 1.002): + return True + return False - # https://superhky.tistory.com/441 - find = False - for c in range(i-40, i-1): - if data['rsi'][i-1] > low_barrier and data['rsi'][i] < low_barrier: - for k in range(c, i): - if data['rsi'][k-1] < low_barrier and data['rsi'][k] > low_barrier: - temp01 = data['rsi'].iloc[c:k] - temp01_id = temp01.argmin() + c - temp01_min_rsi = data['rsi'][temp01_id] - temp01_min_price = data['close'][temp01_id] + def cosine_similarity(self, x, y): + return np.dot(x, y) / (np.sqrt(np.dot(x, x)) * np.sqrt(np.dot(y, y))) - for m in range(k, i): - if data['rsi'][m-1] < low_barrier and data['rsi'][m] < low_barrier: - for n in range(m, i): - if data['rsi]'][n-1] < low_barrier and data['rsi'][n] < low_barrier: - temp02 = data['rsi'].iloc[m:n] - temp02_id = temp02.argmin() + m - temp02_min_rsi = data['rsi'][temp02_id] - temp02_min_price = data['close'][temp02_id] + """ + def findBuyPoint(self, data, data_signal, i): + # 코사인 유사도(cosine similarity)로 과거 주가의 유사 패턴을 찾아 미래 예측하기 + # https://teddylee777.github.io/pandas/cos-sim-stock/ - if temp01_min_rsi < temp02_min_rsi and temp01_min_price > temp02_min_price and flag == 1: - if c == i-1: - weight = 1 - buy = data['close'][i] - type = 'Divergence' - find = True - break - if find: break - if find: break - if find: break - """ - # 매수전략 #3: stochastic + rsi + macd - check = False - if data['slow_k'][i - 1] < data['slow_k'][i] and data['slow_d'][i] < data['slow_k'][i]: + buy_target = data['close'].iloc[i-179:i+1] + window_size = len(buy_target) + if window_size == 180: + buy_target = (buy_target - buy_target.min()) / (buy_target.max() - buy_target.min()) + for pattern in self.PATTERNS: + cos_similarity = self.cosine_similarity(pattern, buy_target) + if 0.995 < cos_similarity: + return True - # 과매도 체크 - index = -1 - for c in range(i - 40, i): - if data['slow_k'][i] < 20: - index = c - check = True - if check: - # 과매도 후 과매수 였는지 체크 - check = False - for d in range(index, i): - if 80 < data['slow_k'][d]: - check = True - break - if not check: - # 과매도 후 과매수가 아니라면 - if data['rsi'][i - 1] < 50 and 50 < data['rsi'][i]: - if data['macds'][i] < data['macd'][i] < 0: - weight = 1 - buy = data['close'][i] - type = 'S+R+M' - """ - return buy, weight, type + return False + """ + + def findBuyPoint(self, data, i): + # DTW (Dynamic Time Warping) + # 시계열 유사도: https://m.blog.naver.com/happyrachy/221693939341 + if i < 24: + return False + + for p in range(len(self.PATTERNS['min_max'])): + size = len(self.PATTERNS['stndardization'][p]) + if i - size + 1 < 0: + continue + + close = data['close'].iloc[i-size+1:i+1] + + #min_max = np.array(self.PATTERNS['min_max'][p]).reshape(-1, 1) + stndardization = np.array(self.PATTERNS['stndardization'][p]).reshape(-1, 1) + + #min_max_y = np.array((close - close.min()) / (close.max() - close.min())).reshape(-1, 1) + stndardization_y = np.array((close - close.mean()) / close.std()).reshape(-1, 1) + + #manhattan_distance = lambda min_max, min_max_y: np.abs(min_max - min_max_y) + #min_max_d, cost_matrix, acc_cost_matrix, path = dtw(min_max, min_max_y, dist=manhattan_distance) + + manhattan_distance = lambda stndardization, stndardization_y: np.abs(stndardization - stndardization_y) + stndardization_d, cost_matrix, acc_cost_matrix, path = dtw(stndardization, stndardization_y, dist=manhattan_distance) + + if stndardization_d < 2: + #print(i, data['ymd'].iloc[i], stndardization_d) + return True + return False + + def getMacd(self, ticker_code, day, mins=1): + + table = 'minutely_max_macd_' + str(mins) + + conn = sqlite3.connect(os.path.join(self.RESOURCE_PATH, 'coins.db')) + cursor = conn.cursor() + + day1 = (datetime.strptime(day, '%Y%m%d') - timedelta(1)).strftime('%Y%m%d') + cursor.execute('SELECT ymd, hms, macd, close FROM '+table+' WHERE (CODE=? or CODE=?) and (ymd=? or ymd=?) order by macd desc', (ticker_code, ticker_code.replace('KRW-', ''), day, day1, )) + db_result1 = cursor.fetchall() + + cursor.close() + conn.close() + + macd_limit = [(datetime.strptime(rows[0]+" "+rows[1], '%Y%m%d %H%M%S'), rows[2], rows[3]) for rows in db_result1] + macd_dup = list(set(macd_limit)) + return macd_dup + + def getBuyPriceAndWeight1(self, ticker, MAX_BUY_PRICE, i, data, data_signal, BUY_LIST, isRealTime=True): + buy_ymd, buy_price, buy_count, buy_cut, buy_type = None, -1, -1, -1, '' + + df_tmp = data_signal['ymd'] <= data['ymd'][i] + df_signal = data_signal.loc[df_tmp] + si = len(df_signal) - 1 + + if isRealTime: + macds = data['macd'][i-300:i].to_list() + if 0 < len(macds): + macds_max = max(macds) + mi = i-300 + macds.index(macds_max) + + if data['macd'][i] < macds_max and data['close'][mi] < data['close'][i]: + return buy_ymd, buy_price, buy_count, buy_cut, buy_type + else: + return buy_ymd, buy_price, buy_count, buy_cut, buy_type + else: + macds = self.getMacd(ticker['ticker_code'], data['ymd'][i].strftime('%Y%m%d'), mins=1) + if len(macds) == 0: + return buy_ymd, buy_price, buy_count, buy_cut, buy_type + + macds_sort = sorted(macds, key=lambda x:x[0], reverse=True) + if data['macd'][i] < macds_sort[0][1] and macds_sort[0][2] < data['close'][i]: + return buy_ymd, buy_price, buy_count, buy_cut, buy_type + + duration = 3 + if sum(data['trend_avg'][i - duration:i]) / duration < data['trend_avg'][i]: + # 상승 트렌드 + if data_signal['avg20'][si] < data_signal['avg5'][si]: + # 방법 1: + if max(data['volume_up'][i-180:i]) < data['volume_up'][i]: + if data_signal['slow_k'][si] < 70: + if BUY_LIST is not None and 0 < len(BUY_LIST['buy_list']) and BUY_LIST['buy_list'][-1]['buy_price'] < data['close'][i]: + buy_price = data['close'][i] + buy_type = 'volume_up' + buy_ymd = data['ymd'][i] + if data['slow_k'][si] < 30: + buy_count = MAX_BUY_PRICE / (1 * data['close'][i]) + elif data['slow_k'][si] < 50: + buy_count = MAX_BUY_PRICE / (2 * data['close'][i]) + else: + buy_count = MAX_BUY_PRICE / (3 * data['close'][i]) + return buy_ymd, buy_price, buy_count, buy_cut, buy_type + else: + buy_price = data['close'][i] + buy_type = 'volume_up' + buy_ymd = data['ymd'][i] + if data['slow_k'][si] < 30: + buy_count = MAX_BUY_PRICE / (1 * data['close'][i]) + elif data['slow_k'][si] < 50: + buy_count = MAX_BUY_PRICE / (2 * data['close'][i]) + else: + buy_count = MAX_BUY_PRICE / (3 * data['close'][i]) + return buy_ymd, buy_price, buy_count, buy_cut, buy_type + + # 방법 2: + if data['avg480'][i] < data['avg120'][i] < data['avg60'][i] < data['avg20'][i] < data['avg5'][i] < data['close'][i]: + if data['avg240'][i] < min(data['avg5'][i], data['avg20'][i], data['avg60'][i], data['avg120'][i]): + if BUY_LIST is not None and 0 < len(BUY_LIST['buy_list']) and data['ymd'][i] < BUY_LIST['buy_list'][-1]['buy_ymd'] + timedelta(minutes=10): + if BUY_LIST['buy_list'][-1]['buy_price'] < data['close'][i]: + buy_price = data['close'][i] + buy_type = 'golden' + buy_ymd = data['ymd'][i] + if data['slow_k'][si] < 30: + buy_count = MAX_BUY_PRICE / (1 * data['close'][i]) + elif data['slow_k'][si] < 50: + buy_count = MAX_BUY_PRICE / (2 * data['close'][i]) + else: + buy_count = MAX_BUY_PRICE / (3 * data['close'][i]) + else: + buy_price = data['close'][i] + buy_type = 'golden' + buy_ymd = data['ymd'][i] + if data['slow_k'][si] < 30: + buy_count = MAX_BUY_PRICE / (1 * data['close'][i]) + elif data['slow_k'][si] < 50: + buy_count = MAX_BUY_PRICE / (2 * data['close'][i]) + else: + buy_count = MAX_BUY_PRICE / (3 * data['close'][i]) + return buy_ymd, buy_price, buy_count, buy_cut, buy_type - def getSellPriceAndWeight(self, i, data): - sell, weight, type = -1, -1, "" + return buy_ymd, buy_price, buy_count, buy_cut, buy_type - max_value = max(data['macd'].tolist()) * 0.8 - if (max_value < data['macd'][i] or 1.9 < data['macds'][i]) and (0 < data['macdo'][i-1] and data['macdo'][i] <= 0): - #if data['macds'][i-1] < data['macd'][i-1] and data['macd'][i] < data['macds'][i]: - weight = 1 - sell = data['close'][i] - type = 'method1' + def getSellPriceAndWeight1(self, ticker, i, data, data_signal, BUY_LIST=None): + sell_price, sell_count = -1, -1 - # 매수전략 #2: RSI 과매수에서 데드크로스 - if (data['macds'][i - 1] < data['macd'][i - 1] and data['macd'][i] < data['macds'][i]): - if 70 < data['rsi'][i]: - weight = 1 - sell = data['close'][i] - type = 'method2' + if BUY_LIST is not None and 0 < len(BUY_LIST['buy_list']): + # 방법1에 대해서는 1% 이익시 매도 한다. (Upbit.py 파일에서) + # 방법2에 대한 매도 + if data['close'][i-1] < data['open'][i-1] and data['close'][i] < data['open'][i]: + count = sum([price['buy_count'] for price in BUY_LIST['buy_list'] if price['buy_type'] == 'golden']) + if 0 < count: + sell_price = data['close'][i] + sell_count = sum([price['buy_count'] for price in BUY_LIST['buy_list']]) - return sell, weight, type + return sell_price, sell_count + + def checkTransaction1(self, ticker, MAX_BUY_PRICE, data, data_signal, BUY_LIST=None, isRealTime=True): - def checkTransaction(self, data, isRealTime=True): # 어제 오늘 데이터로 분석 bsLine = {} @@ -149,150 +216,52 @@ class BuySellChecker: # isRealTime=True, 실시간 적용 last_index = size - 1 - buy, buy_weight, buy_type = self.getBuyPriceAndWeight(last_index, data) - sell, sell_weight, sell_type = self.getSellPriceAndWeight(last_index, data) - - bsLine['buy'] = [buy] - bsLine['buy_weight'] = [buy_weight] - bsLine['buy_type'] = [buy_type] - bsLine['sell'] = [sell] + sell_price, sell_weight = self.getSellPriceAndWeight1(ticker, last_index, data, data_signal, BUY_LIST) + bsLine['sell_price'] = [sell_price] bsLine['sell_weight'] = [sell_weight] - bsLine['sell_type'] = [sell_type] + buy_ymd, buy_price, buy_count, buy_cut, buy_type = self.getBuyPriceAndWeight1(ticker, MAX_BUY_PRICE, last_index, data, data_signal, BUY_LIST, isRealTime) + bsLine['buy_ymd'] = [buy_ymd] + bsLine['buy_price'] = [buy_price] + bsLine['buy_count'] = [buy_count] + bsLine['buy_cut'] = [buy_cut] + bsLine['buy_type'] = [buy_type] + + if BUY_LIST is not None and 0 < buy_price: + BUY_LIST['buy_list'].append({'buy_ymd': buy_ymd, 'buy_price': buy_price, 'buy_count': buy_count, 'buy_cut': buy_cut, 'buy_type': buy_type}) else: # Type=False, 시뮬레이션 적용 - bsLine['buy'] = [-1 for i in range(size)] - bsLine['buy_weight'] = [-1 for i in range(size)] + bsLine['buy_ymd'] = [-1 for i in range(size)] + bsLine['buy_price'] = [-1 for i in range(size)] + bsLine['buy_count'] = [-1 for i in range(size)] + bsLine['buy_cut'] = [-1 for i in range(size)] bsLine['buy_type'] = ['' for i in range(size)] - bsLine['sell'] = [-1 for i in range(size)] + bsLine['sell_price'] = [-1 for i in range(size)] bsLine['sell_weight'] = [-1 for i in range(size)] - bsLine['sell_type'] = ['' for i in range(size)] for last_index in range(size): - buy, buy_weight, buy_type = self.getBuyPriceAndWeight(last_index, data) - sell, sell_weight, sell_type = self.getSellPriceAndWeight(last_index, data) - bsLine['buy'][last_index] = buy - bsLine['buy_weight'][last_index] = buy_weight - bsLine['buy_type'][last_index] = buy_type - bsLine['sell'][last_index] = sell + sell_price, sell_weight = self.getSellPriceAndWeight1(ticker, last_index, data, data_signal, BUY_LIST) + bsLine['sell_price'][last_index] = sell_price bsLine['sell_weight'][last_index] = sell_weight - bsLine['sell_type'][last_index] = sell_type + + if sell_price < 0: + buy_ymd, buy_price, buy_count, buy_cut, buy_type = self.getBuyPriceAndWeight1(ticker, MAX_BUY_PRICE, last_index, data, data_signal, BUY_LIST, isRealTime) + bsLine['buy_price'][last_index] = buy_price + bsLine['buy_count'][last_index] = buy_count + bsLine['buy_cut'][last_index] = buy_cut + bsLine['buy_type'][last_index] = buy_type + + if BUY_LIST is not None and 0 < buy_price: + BUY_LIST['buy_list'].append({'buy_ymd': buy_ymd, 'buy_price': buy_price, 'buy_count': buy_count, 'buy_cut': buy_cut, 'buy_type': buy_type}) + else: - bsLine['buy'] = [-1] - bsLine['buy_weight'] = [-1] + bsLine['buy_price'] = [-1] + bsLine['buy_count'] = [-1] + bsLine['buy_cut'] = [-1] bsLine['buy_type'] = [''] - bsLine['sell'] = [-1] + bsLine['sell_price'] = [-1] bsLine['sell_weight'] = [-1] - bsLine['sell_type'] = [''] return bsLine - - def analyze(self, result): - # 기본 캔들 정보 - 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=5).mean().fillna(close[0]).values.tolist() - avg5 = [item[0] for item in avg5_list] - avg20_list = close_df.rolling(window=20).mean().fillna(close[0]).values.tolist() - avg20 = [item[0] for item in avg20_list] - avg30_list = close_df.rolling(window=30).mean().fillna(close[0]).values.tolist() - avg30 = [item[0] for item in avg30_list] - avg60_list = close_df.rolling(window=60).mean().fillna(close[0]).values.tolist() - avg60 = [item[0] for item in avg60_list] - avg120_list = close_df.rolling(window=120).mean().fillna(close[0]).values.tolist() - avg120 = [item[0] for item in avg120_list] - avg200_list = close_df.rolling(window=200).mean().fillna(close[0]).values.tolist() - avg200 = [item[0] for item in avg200_list] - - open_df = pd.DataFrame(close) - disparity_avg5_list = (open_df / close_df.rolling(window=5).mean()).values.tolist() - disparity_avg5 = [item[0] for item in disparity_avg5_list] - disparity_avg20_list = (open_df / close_df.rolling(window=20).mean()).values.tolist() - disparity_avg20 = [item[0] for item in disparity_avg20_list] - disparity_avg30_list = (open_df / close_df.rolling(window=30).mean()).values.tolist() - disparity_avg30 = [item[0] for item in disparity_avg30_list] - disparity_avg60_list = (open_df / close_df.rolling(window=60).mean()).values.tolist() - disparity_avg60 = [item[0] for item in disparity_avg60_list] - disparity_avg120_list = (open_df / close_df.rolling(window=120).mean()).values.tolist() - disparity_avg120 = [item[0] for item in disparity_avg120_list] - disparity_avg200_list = (open_df / close_df.rolling(window=200).mean()).values.tolist() - disparity_avg200 = [item[0] for item in disparity_avg200_list] - - # 볼린져 밴드 - df = pd.DataFrame(close) - max20 = df.rolling(window=20).mean() - stddev20 = df.rolling(window=20).std() - upper_df = max20 + (stddev20 * 2) # 상단 볼린저 밴드 - lower_df = max20 - (stddev20 * 2) # 하단 볼린저 밴드 - - upper, lower = [], [] - for i in range(len(upper_df)): - if i < 10: - upper.append(upper_df.values[0][0]) - lower.append(lower_df.values[0][0]) - else: - upper.append(upper_df.values[i][0]) - lower.append(lower_df.values[i][0]) - - point_temp = result["time"] - STOCK = [] - for i in range(len(open)): - STOCK.append({'volume': vol[i], 'close': close[i], 'open': open[i], 'high': high[i], 'low': low[i], - 'avg5': avg5[i], 'avg20': avg20[i], 'avg30': avg30[i], 'avg60': avg60[i], 'avg120': avg120[i], 'avg200': avg200[i]}) - - # stochastic - stochastic_df = self.stochastic.apply(STOCK, n=30, m=5, t=5) - fast_k = stochastic_df['fast_k'].values.tolist() - slow_k = stochastic_df['slow_k'].values.tolist() - slow_d = stochastic_df['slow_d'].values.tolist() - - # macd - #macd_df = self.macd.apply(STOCK, short=12, long=26, t=9) - macd_df = self.macd.apply(STOCK, short=5, long=20, t=5) - macd = macd_df['macd'].values.tolist() - macds = macd_df['macds'].values.tolist() - macdo = macd_df['macdo'].values.tolist() - - # rsi - rsi_df = self.rsi.apply(STOCK, period=30, window=5) - rsi = rsi_df['rsi'].values.tolist() - rsis = rsi_df['rsis'].values.tolist() - - # ichimokuCloud - ichimokuCloud_df = self.ichimokuCloud.apply(STOCK, c=9, b=26, l=52) - ichimokuCloud_df = ichimokuCloud_df[:len(ichimokuCloud_df) - 51] - changeLine = ichimokuCloud_df['changeLine'].values.tolist() - baseLine = ichimokuCloud_df['baseLine'].values.tolist() - laggingSpan = ichimokuCloud_df['laggingSpan'].values.tolist() - leadingSpan1 = ichimokuCloud_df['leadingSpan1'].values.tolist() - leadingSpan2 = ichimokuCloud_df['leadingSpan2'].values.tolist() - - # 결과 - temp = { - "date": point_temp, - "open": open, "high": high, "low": low, "close": close, "volume": vol, - "avg5": avg5, "avg20": avg20, "avg30": avg30, "avg60": avg60, "avg120": avg120, "avg200": avg200, - "disparity_avg5": disparity_avg5, "disparity_avg20": disparity_avg20, "disparity_avg30": disparity_avg30, - "disparity_avg60": disparity_avg60, "disparity_avg120": disparity_avg120, "disparity_avg200": disparity_avg200, - "upper": upper, "lower": lower, - "macd": macd, "macds": macds, "macdo": macdo, - "fast_k": fast_k, "slow_k": slow_k, "slow_d": slow_d, - "rsi": rsi, "rsis": rsis, - "changeLine": changeLine, "baseLine": baseLine, "laggingSpan": laggingSpan, "leadingSpan1": leadingSpan1, - "leadingSpan2": leadingSpan2, - } - - data = pd.DataFrame(temp) - df_final_time = pd.DatetimeIndex(point_temp) - data.index = df_final_time - - data = data.fillna(-1) - return data diff --git a/stock/util/TelegramBot.py b/stock/util/TelegramBot.py index 365fcea..9ed69ca 100644 --- a/stock/util/TelegramBot.py +++ b/stock/util/TelegramBot.py @@ -1,6 +1,7 @@ from datetime import datetime import telegram import asyncio +import platform from multiprocessing import Pool class TelegramBot: @@ -23,9 +24,9 @@ class TelegramBot: username for the bot: ncue_stock_bot token to access the HTTP API: 6874078562:AAEHxGDavfc0ssAXPQIaW8JGYmTR7LNUJOw """ - self.botname = "stockbot" - self.username = "ncue_stock_bot" - self.token = "6874078562:AAEHxGDavfc0ssAXPQIaW8JGYmTR7LNUJOw" + self.botname = "coinbot" + self.username = "ncue_coin_bot" + self.token = "6435061393:AAHOh9wB5yGNGUdb3SfCYJrrWTBe7wgConM" self.chat_id = '574661323' self.client = telegram.Bot(token=self.token) @@ -36,25 +37,29 @@ class TelegramBot: @staticmethod def send(text): - client = telegram.Bot(token="6874078562:AAEHxGDavfc0ssAXPQIaW8JGYmTR7LNUJOw") - #client.sendMessage(chat_id='574661323', text=text) + client = telegram.Bot(token="6435061393:AAHOh9wB5yGNGUdb3SfCYJrrWTBe7wgConM") + if platform.system().lower() == 'windows': + asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) asyncio.run(client.send_message(chat_id='574661323', text=text)) return def alarm_live(self, stock_code, stock_name): if self.enable: this_time = datetime.now() - text = "ALIVE (" + this_time.strftime('%Y-%m-%d %H:%M:%S') + ") " + stock_code + "(" + stock_name +")" + text = "[ALIVE] {} {} ({})".format(this_time.strftime('%H:%M'), stock_code, stock_name) pool = Pool(12) pool.map(self.send, [text]) print(text) return - def post(self, stock_code, stock_name, type, price, count): + def post(self, stock_code, stock_name, type, price, amount, rsi, balance=0): if self.enable: this_time = datetime.now() - text = "DATE TIME:" + this_time.strftime('%Y-%m-%d %H:%M:%S') + ", " + "stock_code:" + stock_code + ", " + "stock_name:" + stock_name + ", " + "type:" + type + ", " + "price:" + str(price) + ", " + "count:" + str(count) + if 0 < balance: + text = "{}, {}, code: {}, name: {}, price: {}, amount: {}, (balance: {:2f}), (rsi: {:2f})".format(type, this_time.strftime('%H:%M'), stock_code, stock_name, price, amount, balance, rsi) + else: + text = "{}, {}, code: {}, name: {}, price: {}, amount: {}, (rsi: {:2f})".format(type, this_time.strftime('%H:%M'), stock_code, stock_name, price, amount, rsi) pool = Pool(12) pool.map(self.send, [text]) print(text) @@ -63,7 +68,7 @@ class TelegramBot: def sendMsg(self, msg): if self.enable: this_time = datetime.now() - text = "DATE TIME:" + this_time.strftime('%Y-%m-%d %H:%M:%S') + ", " + "msg:" + msg + text = "{}: {}".format(this_time.strftime('%H:%M'), msg) pool = Pool(12) pool.map(self.send, [text]) print(text) @@ -76,10 +81,9 @@ if __name__ == "__main__": stock_name = "x2" type = "BUY" price = 2000 - count = 2 telegramBot = TelegramBot() telegramBot.alarm_live(stock_code, stock_name) - telegramBot.post(stock_code, stock_name, type, price, count) + telegramBot.post(stock_code, stock_name, type, price)