From 6438003081ebec9999812306c1d10a550f9068e6 Mon Sep 17 00:00:00 2001 From: dsyoon Date: Wed, 20 Mar 2024 23:07:50 +0900 Subject: [PATCH 1/7] init --- StockCrawler.py | 10 +--------- stock/analysis/AnalyzerSqlite.py | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/StockCrawler.py b/StockCrawler.py index 40ea361..4923b88 100644 --- a/StockCrawler.py +++ b/StockCrawler.py @@ -10,17 +10,13 @@ from stock.crawler.FnGuideCrawler import FnGuideCrawler from stock.crawler.MetaCrawler import MetaCrawler from stock.crawler.StockCrawler import StockCrawler from stock.analysis.AnalyzerSqlite import AnalyzerSqlite -from stock.util.TelegramBot import TelegramBot class StockCrawlerDaily: PROJECT_HOME = None - bot = None - def __init__(self, PROJECT_HOME): self.PROJECT_HOME = PROJECT_HOME - self.bot = TelegramBot() return @@ -136,11 +132,7 @@ class StockCrawlerDaily: shutil.rmtree(outPath) os.mkdir(outPath) - buy_stock_list = analyzerSqlite.findCandidates(outPath) - buy_stock_str = '' - for i, item in enumerate(buy_stock_list): - buy_stock_str += str(i+1) + ". " + item['CODE'] + "(" + item['NAME'] + ")\n" - self.bot.sendMsg("{}".format(buy_stock_str)) + analyzerSqlite.findCandidates(outPath) return diff --git a/stock/analysis/AnalyzerSqlite.py b/stock/analysis/AnalyzerSqlite.py index 9f8422c..2314fe0 100644 --- a/stock/analysis/AnalyzerSqlite.py +++ b/stock/analysis/AnalyzerSqlite.py @@ -22,6 +22,7 @@ from plotly import subplots import plotly.io as po from stock.analysis.Common import Common +from stock.util.TelegramBot import TelegramBot class AnalyzerSqlite: jSDPattern = None @@ -29,6 +30,8 @@ class AnalyzerSqlite: topCompany = None fnguide = None + bot = None + common = None stockFileName = None analyzedFileName = None @@ -45,6 +48,8 @@ class AnalyzerSqlite: self.topCompany = self.getTopCompany(self.stockFileName, 2000) self.fnguide = self.readFnguide(self.stockFileName) + self.bot = TelegramBot() + return def getTopCompany(self, fnguideFileName, top): @@ -658,7 +663,12 @@ class AnalyzerSqlite: self.writeFile(outPath, CODE, NAME, top, stock_daily, bsLine) buy_stock_list.append({'CODE': CODE, 'NAME': NAME}) - return buy_stock_list + buy_stock_str = '' + for i, item in enumerate(buy_stock_list): + buy_stock_str += str(i + 1) + ". " + item['CODE'] + "(" + item['NAME'] + ")\n" + self.bot.sendMsg("{}".format(buy_stock_str)) + + return if __name__ == "__main__": @@ -667,7 +677,7 @@ if __name__ == "__main__": PROJECT_HOME = os.path.join(os.path.dirname(os.path.join(os.path.dirname(os.path.join(os.path.dirname(__file__)))))) RESOURCE_PATH = os.path.join(PROJECT_HOME, 'resources') - analyzer = AnalyzerSqlite(RESOURCE_PATH) + analyzerSqlite = AnalyzerSqlite(RESOURCE_PATH) # HTML 출력 @@ -688,8 +698,8 @@ if __name__ == "__main__": shutil.rmtree(outPath) os.mkdir(outPath) print("print to Html...") - analyzer.findCandidates(outPath) + analyzerSqlite.findCandidates(outPath) print("time : %6.2f 초" % (time.time() - start)) print("done...") From e711a8e3c4413c77a647172276939fa880473d52 Mon Sep 17 00:00:00 2001 From: dsyoon Date: Wed, 20 Mar 2024 23:12:21 +0900 Subject: [PATCH 2/7] init --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index d25885d..309818e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -22,3 +22,4 @@ pybithumb ccxt slack-sdk scikit-learn +python-telegram-bot \ No newline at end of file From abe2d75f5b0611b7b893f89fc444387afd2b17cb Mon Sep 17 00:00:00 2001 From: dsyoon Date: Thu, 21 Mar 2024 00:06:20 +0900 Subject: [PATCH 3/7] init --- stock/analysis/AnalyzerSqlite.py | 4 ++-- stock/util/TelegramBot.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/stock/analysis/AnalyzerSqlite.py b/stock/analysis/AnalyzerSqlite.py index 2314fe0..68e7453 100644 --- a/stock/analysis/AnalyzerSqlite.py +++ b/stock/analysis/AnalyzerSqlite.py @@ -527,8 +527,8 @@ class AnalyzerSqlite: title = "[Summary] bull: %d (%.2f), bear: %d (%.2f), even: %d (%.2f)" % (param['bull'][0], param['bull'][0]/sum, param['bear'][0], param['bear'][0]/sum, param['even'][0], param['even'][0]/sum) fig['layout'].update(title=title) - fileName = "%s/summary.html" % (self.outPath) - po.write_html(fig, file=fileName, auto_open=False) + #fileName = "%s/summary.html" % (self.outPath) + #po.write_html(fig, file=fileName, auto_open=False) return diff --git a/stock/util/TelegramBot.py b/stock/util/TelegramBot.py index 0946877..f572b0c 100644 --- a/stock/util/TelegramBot.py +++ b/stock/util/TelegramBot.py @@ -24,9 +24,9 @@ class TelegramBot: username for the bot: ncue_stock_bot token to access the HTTP API: 6874078562:AAEHxGDavfc0ssAXPQIaW8JGYmTR7LNUJOw """ - self.botname = "coinbot" - self.username = "ncue_coin_bot" - self.token = "6435061393:AAHOh9wB5yGNGUdb3SfCYJrrWTBe7wgConM" + self.botname = "stockbot" + self.username = "ncue_stock_bot" + self.token = "6874078562:AAEHxGDavfc0ssAXPQIaW8JGYmTR7LNUJOw" self.chat_id = '574661323' self.client = telegram.Bot(token=self.token) @@ -37,7 +37,7 @@ class TelegramBot: @staticmethod def send(text): - client = telegram.Bot(token="6435061393:AAHOh9wB5yGNGUdb3SfCYJrrWTBe7wgConM") + client = telegram.Bot(token="6874078562:AAEHxGDavfc0ssAXPQIaW8JGYmTR7LNUJOw") if platform.system().lower() == 'windows': asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) asyncio.run(client.send_message(chat_id='574661323', text=text)) From bb064071bd8f45b0ee3043fbc789e8d85ef147aa Mon Sep 17 00:00:00 2001 From: dsyoon Date: Thu, 21 Mar 2024 00:13:01 +0900 Subject: [PATCH 4/7] init --- stock/analysis/JSDPattern_simulation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stock/analysis/JSDPattern_simulation.py b/stock/analysis/JSDPattern_simulation.py index 6536075..cf6112f 100644 --- a/stock/analysis/JSDPattern_simulation.py +++ b/stock/analysis/JSDPattern_simulation.py @@ -23,7 +23,7 @@ class JSDPattern_simulation (JSDPattern): super().__init__(RESOURCE_PATH) return - def analyze(self, result, mins=1): + def analyze(self, result, mins=1440): result["volume"] = [result["volume"][i] if 0 < result["volume"][i] else 1 for i in range(len(result["volume"]))] # 기본 캔들 정보 open_df = pd.DataFrame(result["open"]) From ca7b558ea714e79251582bb2841bf8bbf3da811c Mon Sep 17 00:00:00 2001 From: dsyoon Date: Thu, 21 Mar 2024 00:46:59 +0900 Subject: [PATCH 5/7] init --- hts/BuySell_Daily.py | 122 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 101 insertions(+), 21 deletions(-) diff --git a/hts/BuySell_Daily.py b/hts/BuySell_Daily.py index 807de97..ed79db0 100644 --- a/hts/BuySell_Daily.py +++ b/hts/BuySell_Daily.py @@ -10,26 +10,50 @@ class BuySell_Daily: count += 1 return count - def getBuyPrice(self, data, i, BS=None): + def getBuyPrice(self, ticker, data, i, BS=None): buy_ymd, buy_price, buy_count, buy_weight, buy_type, buy_cut = None, 0, 0, 1, '', None - tmp_buy_ymd, tmp_buy_price, tmp_buy_count, tmp_buy_type, tmp_buy_cut = self.getBuyPrice_ichimok_changeLine(data, i, BS) + point = None + for c in range(i-1, 0, -1): + if data['close'][c] < data['changeLine'][c]: + point = c + break + if point is not None: + if 3 < sum([1 if 0 < BS['buy_price'][k] else 0 for k in range(point, i)]): + return buy_ymd, 0, 0, '', None + + tmp_buy_ymd, tmp_buy_price, tmp_buy_count, tmp_buy_type, tmp_buy_cut = self.getBuyPrice_ichimok_changeLine(ticker, data, i, BS) if 0 < tmp_buy_count: buy_ymd = tmp_buy_ymd; buy_price = tmp_buy_price; buy_count = tmp_buy_count; buy_type = tmp_buy_type; buy_cut = tmp_buy_cut - tmp_buy_ymd, tmp_buy_price, tmp_buy_count, tmp_buy_type, tmp_buy_cut = self.getBuyPrice_ichimok_baseLine(data, i, BS) + tmp_buy_ymd, tmp_buy_price, tmp_buy_count, tmp_buy_type, tmp_buy_cut = self.getBuyPrice_ichimok_baseLine(ticker, data, i, BS) if 0 < tmp_buy_count: buy_ymd = tmp_buy_ymd; buy_price = tmp_buy_price; buy_count = tmp_buy_count; buy_type = tmp_buy_type; buy_cut = tmp_buy_cut - tmp_buy_ymd, tmp_buy_price, tmp_buy_count, tmp_buy_type, tmp_buy_cut = self.getBuyPrice_ichimok_laggingSpan(data, i, BS) + tmp_buy_ymd, tmp_buy_price, tmp_buy_count, tmp_buy_type, tmp_buy_cut = self.getBuyPrice_ichimok_laggingSpan(ticker, data, i, BS) if 0 < tmp_buy_count: buy_ymd = tmp_buy_ymd; buy_price = tmp_buy_price; buy_count = tmp_buy_count; buy_type = tmp_buy_type; buy_cut = tmp_buy_cut + tmp_buy_ymd, tmp_buy_price, tmp_buy_count, tmp_buy_type, tmp_buy_cut = self.getBuyPrice_ichimok_avg(ticker, data, i, BS) + if 0 < tmp_buy_count: + buy_ymd = tmp_buy_ymd; buy_price = tmp_buy_price; buy_count = tmp_buy_count; buy_type = tmp_buy_type; buy_cut = tmp_buy_cut + + if 0 < len(ticker['BUY_INFO']['buy_list']): + diff = (datetime.strptime(str(data['ymd'][i]), '%Y-%m-%d %H:%M:%S') - ticker['BUY_INFO']['buy_list'][-1]['buy_ymd']) + d = diff.days + s = diff.seconds + + # 해당 종목에 대해서 1분 이내 매수 금지 + if s < 3 * 60: + return buy_ymd, 0, 0, '', None return buy_ymd, buy_price, buy_count, buy_type, buy_cut - def getSellPrice(self, data, i, BS=None): + def getSellPrice(self, ticker, data, i, BS=None): sell_price, sell_count, sell_type = 0, 1, '' sell_type_list = [] - tmp_sell_price, tmp_sell_type_list = self.getSellPrice_ichimok_baseLine(data, i, BS) + tmp_sell_price, tmp_sell_type_list = self.getSellPrice_ichimok_baseLine(ticker, data, i, BS) + sell_type_list += tmp_sell_type_list + + tmp_sell_price, tmp_sell_type_list = self.getSellPrice_candle(ticker, data, i, BS) sell_type_list += tmp_sell_type_list sell_price = tmp_sell_price @@ -39,7 +63,7 @@ class BuySell_Daily: return sell_price, sell_count, sell_type - def getBuyPrice_ichimok_changeLine(self, data, i, BS=None): + def getBuyPrice_ichimok_changeLine(self, ticker, data, i, BS=None): buy_ymd, buy_price, buy_count, buy_weight, buy_type, buy_cut = None, 0, 0, 1, '', None @@ -81,8 +105,8 @@ class BuySell_Daily: if check: buy_ymd = data['ymd'][i] - buy_price = data['close'][i] - buy_count = buy_weight + buy_price = data['close'][i] - 2 * ticker['unit'] + buy_count = (buy_weight * ticker['MAX_BUY']) / data['close'][i] return buy_ymd, buy_price, buy_count, buy_type, buy_cut @@ -90,7 +114,7 @@ class BuySell_Daily: """""""""""""""""" """""""""""""""""" - def getBuyPrice_ichimok_baseLine(self, data, i, BS=None): + def getBuyPrice_ichimok_baseLine(self, ticker, data, i, BS=None): buy_ymd, buy_price, buy_count, buy_weight, buy_type, buy_cut = None, 0, 0, 1, '', None @@ -120,15 +144,15 @@ class BuySell_Daily: if check: buy_ymd = data['ymd'][i] - buy_price = data['close'][i] - buy_count = buy_weight + buy_price = data['close'][i] - 2 * ticker['unit'] + buy_count = (buy_weight * ticker['MAX_BUY']) / data['close'][i] return buy_ymd, buy_price, buy_count, buy_type, buy_cut """""""""""""""""" """""""""""""""""" - def getBuyPrice_ichimok_laggingSpan(self, data, i, BS): + def getBuyPrice_ichimok_laggingSpan(self, ticker, data, i, BS): buy_ymd, buy_price, buy_count, buy_weight, buy_type, buy_cut = None, 0, 0, 1, '', None @@ -138,28 +162,29 @@ class BuySell_Daily: if data['laggingSpan_close_diff_rate'][i-1] <= 0 and 0 < data['laggingSpan_close_diff_rate'][i]: check = True - buy_price = data['close'][i] - buy_count = buy_weight + buy_price = data['close'][i] - 2 * ticker['unit'] + buy_count = (buy_weight * ticker['MAX_BUY']) / data['close'][i] buy_weight = 2 buy_type = 'laggingSpan1' if 0 <= data['laggingSpan_avg60_diff_rate'][i-1] and data['laggingSpan_avg60_diff_rate'][i] < 0: check = True - buy_price = data['close'][i] - buy_count = buy_weight + buy_price = data['close'][i] - 2 * ticker['unit'] + buy_count = (buy_weight * ticker['MAX_BUY']) / data['close'][i] buy_weight = 2 buy_type = 'laggingSpan2' if check: - buy_price = data['close'][i] - buy_count = buy_weight + buy_ymd = data['ymd'][i] + buy_price = data['close'][i] - 2 * ticker['unit'] + buy_count = (buy_weight * ticker['MAX_BUY']) / data['close'][i] return buy_ymd, buy_price, buy_count, buy_type, buy_cut """""""""""""""""" """""""""""""""""" - def getSellPrice_ichimok_baseLine(self, data, i, BS=None): + def getSellPrice_ichimok_baseLine(self, ticker, data, i, BS=None): sell_price = 0 sell_type_list = [] @@ -173,6 +198,61 @@ class BuySell_Daily: sell_type_list.append('ichimok_baseLine') if check: - sell_price = data['close'][i] + sell_price = data['close'][i] + 2 * ticker['unit'] + + return sell_price, sell_type_list + + """""""""""""""""" + """""""""""""""""" + + def getBuyPrice_ichimok_avg(self, ticker, data, i, BS): + + buy_ymd, buy_price, buy_count, buy_weight, buy_type, buy_cut = None, 0, 0, 1, '', None + + check = False + + if 5 < i: + + if data['avg5'][i] < data['avg20'][i] < data['baseLine'][i] < data['changeLine'][i] < data['close'][i]: + if data['avg5'][i-1] Date: Thu, 21 Mar 2024 01:23:30 +0900 Subject: [PATCH 6/7] init --- stock/analysis/AnalyzerSqlite.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stock/analysis/AnalyzerSqlite.py b/stock/analysis/AnalyzerSqlite.py index 68e7453..d672eda 100644 --- a/stock/analysis/AnalyzerSqlite.py +++ b/stock/analysis/AnalyzerSqlite.py @@ -606,14 +606,14 @@ class AnalyzerSqlite: for i in range(start, size): # 매도 확인 - sell_price, sell_count, sell_type = self.buySell_Daily.getSellPrice(data, i, bsLine) + sell_price, sell_count, sell_type = self.buySell_Daily.getSellPrice(ticker, data, i, bsLine) bsLine['sell_price'][i] = sell_price bsLine['sell_count'][i] = sell_count bsLine['sell_type'][i] = sell_type bsLine['sell_cut'][i] = 0 if sell_price < 1: - buy_ymd, buy_price, buy_count, buy_type, buy_cut = self.buySell_Daily.getBuyPrice(data, i, bsLine) + buy_ymd, buy_price, buy_count, buy_type, buy_cut = self.buySell_Daily.getBuyPrice(ticker, data, i, bsLine) bsLine['buy_ymd'][i] = buy_ymd bsLine['buy_price'][i] = buy_price From 9a194cd839f60b59253c104b66bfa42528e9fc72 Mon Sep 17 00:00:00 2001 From: dsyoon Date: Thu, 21 Mar 2024 01:27:29 +0900 Subject: [PATCH 7/7] init --- stock/analysis/AnalyzerSqlite.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stock/analysis/AnalyzerSqlite.py b/stock/analysis/AnalyzerSqlite.py index d672eda..892b847 100644 --- a/stock/analysis/AnalyzerSqlite.py +++ b/stock/analysis/AnalyzerSqlite.py @@ -585,7 +585,6 @@ class AnalyzerSqlite: return def checkTransaction(self, ticker, data, ci): - # 어제 오늘 데이터로 분석 bsLine = {} @@ -645,11 +644,12 @@ class AnalyzerSqlite: for idx, item in enumerate(items): CODE = item[0] NAME = item[1] + ticker = {'ticker_code': CODE, 'ticker_name': NAME, 'unit': 0, 'MAX_BUY': 10000, 'BUY_INFO': {'buy_list': []}} print("#", idx, ", CODE: ", CODE, ", NAME: ", NAME) - CODE = item[0] + stock_daily, ci = self.getStockData(CODE) - bsLine = self.checkTransaction(CODE, stock_daily, ci) + bsLine = self.checkTransaction(ticker, stock_daily, ci) if bsLine['buy_ymd'][ci-1] is not None: top = "0"