Merge remote-tracking branch 'origin/master'

This commit is contained in:
dsyoon
2024-03-22 00:24:43 +09:00
5 changed files with 124 additions and 41 deletions

View File

@@ -10,17 +10,13 @@ from stock.crawler.FnGuideCrawler import FnGuideCrawler
from stock.crawler.MetaCrawler import MetaCrawler from stock.crawler.MetaCrawler import MetaCrawler
from stock.crawler.StockCrawler import StockCrawler from stock.crawler.StockCrawler import StockCrawler
from stock.analysis.AnalyzerSqlite import AnalyzerSqlite from stock.analysis.AnalyzerSqlite import AnalyzerSqlite
from stock.util.TelegramBot import TelegramBot
class StockCrawlerDaily: class StockCrawlerDaily:
PROJECT_HOME = None PROJECT_HOME = None
bot = None
def __init__(self, PROJECT_HOME): def __init__(self, PROJECT_HOME):
self.PROJECT_HOME = PROJECT_HOME self.PROJECT_HOME = PROJECT_HOME
self.bot = TelegramBot()
return return
@@ -136,11 +132,7 @@ class StockCrawlerDaily:
shutil.rmtree(outPath) shutil.rmtree(outPath)
os.mkdir(outPath) os.mkdir(outPath)
buy_stock_list = analyzerSqlite.findCandidates(outPath) 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))
return return

View File

@@ -10,26 +10,50 @@ class BuySell_Daily:
count += 1 count += 1
return count 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 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: 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 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: 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 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: 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 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 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_price, sell_count, sell_type = 0, 1, ''
sell_type_list = [] 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_type_list += tmp_sell_type_list
sell_price = tmp_sell_price sell_price = tmp_sell_price
@@ -39,7 +63,7 @@ class BuySell_Daily:
return sell_price, sell_count, sell_type 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 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: if check:
buy_ymd = data['ymd'][i] buy_ymd = data['ymd'][i]
buy_price = data['close'][i] buy_price = data['close'][i] - 2 * ticker['unit']
buy_count = buy_weight buy_count = (buy_weight * ticker['MAX_BUY']) / data['close'][i]
return buy_ymd, buy_price, buy_count, buy_type, buy_cut 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 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: if check:
buy_ymd = data['ymd'][i] buy_ymd = data['ymd'][i]
buy_price = data['close'][i] buy_price = data['close'][i] - 2 * ticker['unit']
buy_count = buy_weight buy_count = (buy_weight * ticker['MAX_BUY']) / data['close'][i]
return buy_ymd, buy_price, buy_count, buy_type, buy_cut 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 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]: if data['laggingSpan_close_diff_rate'][i-1] <= 0 and 0 < data['laggingSpan_close_diff_rate'][i]:
check = True check = True
buy_price = data['close'][i] buy_price = data['close'][i] - 2 * ticker['unit']
buy_count = buy_weight buy_count = (buy_weight * ticker['MAX_BUY']) / data['close'][i]
buy_weight = 2 buy_weight = 2
buy_type = 'laggingSpan1' buy_type = 'laggingSpan1'
if 0 <= data['laggingSpan_avg60_diff_rate'][i-1] and data['laggingSpan_avg60_diff_rate'][i] < 0: if 0 <= data['laggingSpan_avg60_diff_rate'][i-1] and data['laggingSpan_avg60_diff_rate'][i] < 0:
check = True check = True
buy_price = data['close'][i] buy_price = data['close'][i] - 2 * ticker['unit']
buy_count = buy_weight buy_count = (buy_weight * ticker['MAX_BUY']) / data['close'][i]
buy_weight = 2 buy_weight = 2
buy_type = 'laggingSpan2' buy_type = 'laggingSpan2'
if check: if check:
buy_price = data['close'][i] buy_ymd = data['ymd'][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 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_price = 0
sell_type_list = [] sell_type_list = []
@@ -173,6 +198,61 @@ class BuySell_Daily:
sell_type_list.append('ichimok_baseLine') sell_type_list.append('ichimok_baseLine')
if check: 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]<data['avg5'][i] and data['avg20'][i-1]<data['avg20'][i] and data['baseLine'][i-1]<=data['baseLine'][i] and data['changeLine'][i-1]<data['changeLine'][i]:
check = True
buy_price = data['close'][i] - 2 * ticker['unit']
buy_count = (buy_weight * ticker['MAX_BUY']) / data['close'][i]
buy_weight = 2
buy_type = 'ichimok_avg1'
if data['avg20'][i] < data['baseLine'][i] < data['changeLine'][i] < data['avg5'][i] < data['close'][i]:
if data['avg20'][i-1]<data['avg20'][i] and data['baseLine'][i]<data['baseLine'][i-1] and data['changeLine'][i-1]<data['changeLine'][i] and data['avg5'][i-1]<data['avg5'][i]:
check = True
buy_price = data['close'][i] - 2 * ticker['unit']
buy_count = (buy_weight * ticker['MAX_BUY']) / data['close'][i]
buy_weight = 2
buy_type = 'ichimok_avg2'
if check:
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_candle(self, ticker, data, i, BS=None):
sell_price = 0
sell_type_list = []
check = False
high = max(data['close'][i], data['open'][i])
low = min(data['close'][i], data['open'][i])
if low - data['low'][i] < data['high'][i] - high:
check = True
sell_type_list.append('candle_tail')
if check:
sell_price = data['close'][i] + 2 * ticker['unit']
return sell_price, sell_type_list return sell_price, sell_type_list

View File

@@ -22,3 +22,4 @@ pybithumb
ccxt ccxt
slack-sdk slack-sdk
scikit-learn scikit-learn
python-telegram-bot

View File

@@ -22,6 +22,7 @@ from plotly import subplots
import plotly.io as po import plotly.io as po
from stock.analysis.Common import Common from stock.analysis.Common import Common
from stock.util.TelegramBot import TelegramBot
class AnalyzerSqlite: class AnalyzerSqlite:
jSDPattern = None jSDPattern = None
@@ -29,6 +30,8 @@ class AnalyzerSqlite:
topCompany = None topCompany = None
fnguide = None fnguide = None
bot = None
common = None common = None
stockFileName = None stockFileName = None
analyzedFileName = None analyzedFileName = None
@@ -45,6 +48,8 @@ class AnalyzerSqlite:
self.topCompany = self.getTopCompany(self.stockFileName, 2000) self.topCompany = self.getTopCompany(self.stockFileName, 2000)
self.fnguide = self.readFnguide(self.stockFileName) self.fnguide = self.readFnguide(self.stockFileName)
self.bot = TelegramBot()
return return
def getTopCompany(self, fnguideFileName, top): def getTopCompany(self, fnguideFileName, top):
@@ -522,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) 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) fig['layout'].update(title=title)
fileName = "%s/summary.html" % (self.outPath) #fileName = "%s/summary.html" % (self.outPath)
po.write_html(fig, file=fileName, auto_open=False) #po.write_html(fig, file=fileName, auto_open=False)
return return
@@ -580,7 +585,6 @@ class AnalyzerSqlite:
return return
def checkTransaction(self, ticker, data, ci): def checkTransaction(self, ticker, data, ci):
# 어제 오늘 데이터로 분석 # 어제 오늘 데이터로 분석
bsLine = {} bsLine = {}
@@ -601,14 +605,14 @@ class AnalyzerSqlite:
for i in range(start, size): 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_price'][i] = sell_price
bsLine['sell_count'][i] = sell_count bsLine['sell_count'][i] = sell_count
bsLine['sell_type'][i] = sell_type bsLine['sell_type'][i] = sell_type
bsLine['sell_cut'][i] = 0 bsLine['sell_cut'][i] = 0
if sell_price < 1: 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_ymd'][i] = buy_ymd
bsLine['buy_price'][i] = buy_price bsLine['buy_price'][i] = buy_price
@@ -640,11 +644,12 @@ class AnalyzerSqlite:
for idx, item in enumerate(items): for idx, item in enumerate(items):
CODE = item[0] CODE = item[0]
NAME = item[1] 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) print("#", idx, ", CODE: ", CODE, ", NAME: ", NAME)
CODE = item[0]
stock_daily, ci = self.getStockData(CODE) 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: if bsLine['buy_ymd'][ci-1] is not None:
top = "0" top = "0"
@@ -658,7 +663,12 @@ class AnalyzerSqlite:
self.writeFile(outPath, CODE, NAME, top, stock_daily, bsLine) self.writeFile(outPath, CODE, NAME, top, stock_daily, bsLine)
buy_stock_list.append({'CODE': CODE, 'NAME': NAME}) 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__": 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__)))))) 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') RESOURCE_PATH = os.path.join(PROJECT_HOME, 'resources')
analyzer = AnalyzerSqlite(RESOURCE_PATH) analyzerSqlite = AnalyzerSqlite(RESOURCE_PATH)
# HTML 출력 # HTML 출력
@@ -688,8 +698,8 @@ if __name__ == "__main__":
shutil.rmtree(outPath) shutil.rmtree(outPath)
os.mkdir(outPath) os.mkdir(outPath)
print("print to Html...") print("print to Html...")
analyzer.findCandidates(outPath)
analyzerSqlite.findCandidates(outPath)
print("time : %6.2f" % (time.time() - start)) print("time : %6.2f" % (time.time() - start))
print("done...") print("done...")

View File

@@ -23,7 +23,7 @@ class JSDPattern_simulation (JSDPattern):
super().__init__(RESOURCE_PATH) super().__init__(RESOURCE_PATH)
return 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"]))] 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"]) open_df = pd.DataFrame(result["open"])