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.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

View File

@@ -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]<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

View File

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

View File

@@ -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):
@@ -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)
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
@@ -580,7 +585,6 @@ class AnalyzerSqlite:
return
def checkTransaction(self, ticker, data, ci):
# 어제 오늘 데이터로 분석
bsLine = {}
@@ -601,14 +605,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
@@ -640,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"
@@ -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...")

View File

@@ -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"])