diff --git a/stock/analysis/AnalyzerSqlite.py b/stock/analysis/AnalyzerSqlite.py
index 9e8f91d..eb0bf73 100644
--- a/stock/analysis/AnalyzerSqlite.py
+++ b/stock/analysis/AnalyzerSqlite.py
@@ -262,35 +262,7 @@ class AnalyzerSqlite:
return energy1, energy2
- def makeDir(self, dir_code, dir_name):
- if os.path.isdir(self.outPath + "/" + dir_code+"_"+dir_name):
- os.rmdir(self.outPath + "/" + dir_code+"_"+dir_name)
- os.mkdir(self.outPath + "/" + dir_code+"_"+dir_name)
- return
-
- def makeDirectory(self, outPath):
- self.outPath = outPath
- if os.path.isdir(outPath):
- shutil.rmtree(outPath)
- os.mkdir(outPath)
- self.makeDir("0", "final")
-
- self.makeDir("1", "monthly_macd_-300이하")
- self.makeDir("2", "monthly_rsi_20이하")
- self.makeDir("3", "monthly_EV하단위로_올라옴")
-
- self.makeDir("11", "daily_macd_-1000이하")
- self.makeDir("12", "daily_weekly_monthly_rsi_10_20_30이하")
- self.makeDir("13", "daily_이전에_없던_거래량")
- self.makeDir("14", "daily_이격도")
- self.makeDir("15", "daily_낙폭과대")
- self.makeDir("16", "daily_EV하단_내려옴")
- self.makeDir("17", "daily_BB하단_내려옴")
- self.makeDir("18", "daily_rsi_20이하")
-
- return
-
- def writeFile(self, dir_code, dir_name, CODE, NAME, top, stock, state, final_status_count=-1):
+ def writeFile(self, dir_name, CODE, NAME, top, stock, state, final_status_count=-1):
# 3년 이내 한번이라도 영업이익이 났는지 체크를 함
fnguide = None
if CODE in self.fnguide:
@@ -304,15 +276,11 @@ class AnalyzerSqlite:
if check:
fig = self.draw(stock)
- title = "%s (%s), %d, %s 차트 (URL1, URL2)" % (NAME, CODE, stock['close'][0], dir_code+"_"+dir_name, CODE, CODE)
+ title = "%s (%s), %d, %s 차트 (URL1, URL2)" % (NAME, CODE, stock['close'][0], dir_name, CODE, CODE)
fig['layout'].update(title=title)
- fileName = self.outPath + "/" + dir_code+"_"+dir_name
-
- if dir_code in ("0", "6", "26"):
- fileName = "%s/%s_%s_%s_%s_%s.html" % (fileName, str(final_status_count), top, NAME.replace(" ", ""), CODE, state)
- else:
- fileName = "%s/%s_%s_%s_%s.html" % (fileName, state, NAME.replace(" ", ""), CODE, top)
+ fileName = self.outPath + "/" + dir_name
+ fileName = "%s/%s_%s_%s_%s.html" % (fileName, state, NAME.replace(" ", ""), CODE, top)
po.write_html(fig, file=fileName, auto_open=False)
return
@@ -427,6 +395,37 @@ class AnalyzerSqlite:
return stock
+
+ def makeDir(self, dir_name):
+ if os.path.isdir(self.outPath + "/" + dir_name):
+ os.rmdir(self.outPath + "/" + dir_name)
+ os.mkdir(self.outPath + "/" + dir_name)
+ return
+
+ def makeDirectory(self, outPath):
+ self.outPath = outPath
+ if os.path.isdir(outPath):
+ shutil.rmtree(outPath)
+ os.mkdir(outPath)
+ self.makeDir("final")
+
+ self.makeDir("monthly_macd_n이하")
+ self.makeDir("monthly_rsi_n이하")
+
+ self.makeDir("weekly_macd_n이하")
+ self.makeDir("weekly_rsi_n이하")
+
+ self.makeDir("daily_macd_n이하")
+ self.makeDir("daily_rsi_n이하")
+
+ self.makeDir("daily_이전에_없던_거래량")
+ self.makeDir("daily_이격도")
+ self.makeDir("daily_낙폭과대")
+ self.makeDir("daily_EV하단_내려옴")
+ self.makeDir("daily_BB하단_내려옴")
+
+ return
+
# 후보 찾기
def findCandidates(self, outPath):
self.makeDirectory(outPath)
@@ -460,161 +459,113 @@ class AnalyzerSqlite:
stock_weekly = self.getStockData(stockAnalysisWeeklyTableName, CODE)
stock_monthly = self.getStockData(stockAnalysisMonthlyTableName, CODE)
- status = ""
final_status = ""
final_status_count = 0
- # 거래량이 100만 이상이고, 종가가 1천원 이상인지 체크 (https://happpy-rich.tistory.com/94)
- if stock_weekly['volume'][0] > 100000 and stock_weekly['close'][0] > 1000:
+ # 거래량이 10만 이상이고, 종가가 1천원 이상인지 체크 (https://happpy-rich.tistory.com/94)
+ if stock_daily['volume'][0] > 100000 and stock_daily['close'][0] > 1000:
# 종목 상태 체크 분석
- # MACD가 -300 이하에서 macd가 macds 위로 올라온 경우
- if len(stock_monthly['close']) > 1:
- if stock_monthly['macd'][1] is not None and stock_monthly['macds'][1] is not None and stock_monthly['macd'][0] is not None and stock_monthly['macds'][0] is not None:
- if stock_monthly['macd'][0] <= -300:
- if stock_monthly['macd'][1] < stock_monthly['macds'][1] and stock_monthly['macds'][0] < stock_monthly['macds'][0]:
- dir_code = "1"
- dir_name = "monthly_macd_-300이하"
- final_status_count += 1
- status = "{:.2f}".format(stock_monthly['macd'][0]) + "_" + status
- self.writeFile(dir_code, dir_name, CODE, NAME, top, stock_monthly, status)
- # RSI가 20 이하인 경우, rsi가 rsis위로 올라온 경우
- if len(stock_monthly['close']) > 1:
- if stock_monthly['rsi'][0] is not None and stock_monthly['rsi'][1] is not None and stock_monthly['rsis'][0] is not None and stock_monthly['rsis'][1] is not None:
- if stock_monthly['rsi'][0] <= 20:
- if stock_monthly['rsi'][1] < stock_monthly['rsis'][1] and stock_monthly['rsis'][0] < stock_monthly['rsi'][0]:
- dir_code = "2"
- dir_name = "monthly_rsi_20이하"
- final_status_count += 1
- status = "{:.2f}".format(stock_monthly['rsi'][0]) + "_" + status
- self.writeFile(dir_code, dir_name, CODE, NAME, top, stock_monthly, status)
+ # Monthly 체크
+ if len(stock_monthly['volume']) > 100:
- if len(stock_monthly['volume']) > 5:
- if stock_monthly['envelope_lower'][0] is not None and stock_monthly['envelope_lower'][1] is not None:
- # env 하단에 부딪힘
- if stock_monthly['close'][1] < stock_monthly['envelope_lower'][1] and stock_monthly['envelope_lower'][0] < stock_monthly['close'][0]:
- if stock_daily['close'][1] < stock_daily['avg5'][1] and stock_daily['avg5'][0] < stock_daily['close'][0]:
- dir_code = "3"
- dir_name = "monthly_EV하단위로_올라옴"
- status = str(top) + "_" + status
- final_status_count += 1
- self.writeFile(dir_code, dir_name, CODE, NAME, top, stock_monthly, status)
+ # MACD가 -300 이하에서 macd가 macds 위로 올라온 경우
+ check = self.common.check_macd(stock_monthly, -300)
+ if check:
+ dir_name = "monthly_macd_n이하"
+ final_status_count += 1
+ log = "{:.2f}".format(stock_monthly['macd'][0])
+ self.writeFile(dir_name, CODE, NAME, top, stock_monthly, log)
+ # RSI가 20 이하인 경우, rsi가 rsis위로 올라온 경우
+ check = self.common.check_rsi(stock_monthly, 20)
+ if check:
+ dir_name = "monthly_rsi_n이하"
+ final_status_count += 1
+ log = "{:.2f}".format(stock_monthly['rsi'][0])
+ self.writeFile(dir_name, CODE, NAME, top, stock_monthly, log)
+
+ # Weekly 체크
+ if len(stock_weekly['volume']) > 100:
+
+ # MACD가 -300 이하에서 macd가 macds 위로 올라온 경우
+ check = self.common.check_macd(stock_weekly, -300)
+ if check:
+ dir_name = "weekly_macd_n이하"
+ final_status_count += 1
+ log = "{:.2f}".format(stock_weekly['macd'][0])
+ self.writeFile(dir_name, CODE, NAME, top, stock_weekly, log)
+
+ # RSI가 20 이하인 경우, rsi가 rsis위로 올라온 경우
+ check = self.common.check_rsi(stock_weekly, 20)
+ if check:
+ dir_name = "weekly_rsi_n이하"
+ final_status_count += 1
+ log = "{:.2f}".format(stock_weekly['rsi'][0])
+ self.writeFile(dir_name, CODE, NAME, top, stock_weekly, log)
# 2) daily
if len(stock_daily['volume']) > 100:
- # MSCD -500 이하인 경우
- if stock_daily['macd'][1] is not None and stock_daily['macds'][1] is not None and stock_daily['macd'][0] is not None and stock_daily['macds'][0] is not None:
- if stock_daily['macd'][0] <= -1000:
- if stock_daily['macd'][1] < stock_daily['macds'][1] and stock_daily['macds'][0] < stock_daily['macds'][0]:
- dir_code = "11"
- dir_name = "daily_macd_-1000이하"
- final_status_count += 1
- status = "{:.2f}".format(stock_daily['macd'][0]) + "_" + status
- self.writeFile(dir_code, dir_name, CODE, NAME, top, stock_daily, status)
+ check = self.common.check_macd(stock_daily, -1000)
+ if check:
+ dir_name = "daily_macd_n이하"
+ final_status_count += 1
+ log = "{:.2f}".format(stock_daily['macd'][0])
+ self.writeFile(dir_name, CODE, NAME, top, stock_daily, log)
+
+ # RSI가 10 이하인 경우
+ check = self.common.check_rsi(stock_daily, 10)
+ if check:
+ dir_name = "daily_rsi_n이하"
+ final_status_count += 1
+ log = "{:.2f}".format(stock_daily['macd'][0])
+ self.writeFile(dir_name, CODE, NAME, top, stock_daily, log)
- # daily_weekly_monthly_rsi_10_20_30이하
- if len(stock_monthly['close']) > 1:
- if stock_monthly['rsi'][0] is not None and stock_weekly['rsi'][0] is not None and stock_daily['rsi'][0] is not None:
- if stock_monthly['rsi'][0] < 30 and stock_weekly['rsi'][0] < 20 and stock_daily['rsi'][0] < 10:
- dir_code = "12"
- dir_name = "daily_weekly_monthly_rsi_10_20_30이하"
- status = str(top) + "_" + status
- final_status_count += 1
- self.writeFile(dir_code, dir_name, CODE, NAME, top, stock_daily, status)
# 52주 200일 기준 평균 + 50% 보다 높은 거래량의 경우
- c_index = 200
- if len(stock_daily['volume']) < c_index:
- c_index = len(stock_daily['volume'])
- max_volume = max(stock_daily['volume'][1:c_index])
- if max_volume < stock_daily['volume'][0]:
- dir_code = "13"
+ check, log = self.common.check_volume(stock_daily)
+ if check:
dir_name = "daily_이전에_없던_거래량"
final_status_count += 1
- status = "{:.2f}".format((stock_daily['volume'][0] - max_volume)/max_volume)
- self.writeFile(dir_code, dir_name, CODE, NAME, top, stock_daily, status)
+ self.writeFile(dir_name, CODE, NAME, top, stock_daily, log)
# daily_이격도
- if (98 0.6:
- if stock_daily['stochastic_slow_k'][0] is not None and stock_daily['stochastic_slow_k'][1] is not None and stock_daily['stochastic_slow_d'][1] is not None and stock_daily['stochastic_slow_d'][0] is not None and stock_monthly['stochastic_slow_k'][0] is not None:
- if stock_daily['stochastic_slow_k'][0] < 20 and (stock_daily['stochastic_slow_k'][1] < stock_daily['stochastic_slow_d'][1] and stock_daily['stochastic_slow_d'][0] < stock_monthly['stochastic_slow_k'][0]):
- dir_code = "15"
- dir_name = "daily_낙폭과대"
- final_status_count += 1
- status = str(top) + "_" + status
- self.writeFile(dir_code, dir_name, CODE, NAME, top, stock_daily, status)
+ # daily_EV하단_내려옴
+ check = self.common.check_under_EV_Low(stock_daily)
+ if check:
+ dir_name = "daily_EV하단_내려옴"
+ log = str(top)
+ final_status_count += 1
+ self.writeFile(dir_name, CODE, NAME, top, stock_daily, log)
- if len(stock_daily['volume']) > 5:
- if stock_daily['envelope_lower'][0] is not None and stock_daily['envelope_lower'][1] is not None:
- # ev 하단에 부딪힘
- if stock_daily['close'][1] < stock_daily['avg5'][1] and stock_daily['avg5'][0] < stock_daily['close'][0]:
- check = False
- for c in range(1, 4):
- if stock_daily['close'][c] < stock_daily['envelope_lower'][c]:
- check = True
- break
- if check:
- dir_code = "16"
- dir_name = "daily_EV하단_내려옴"
- status = str(top) + "_" + status
- final_status_count += 1
- self.writeFile(dir_code, dir_name, CODE, NAME, top, stock_daily, status)
+ check = self.common.check_under_BB_Low(stock_daily)
+ if check:
+ dir_name = "daily_BB하단_내려옴"
+ log = str(top)
+ final_status_count += 1
+ self.writeFile(dir_name, CODE, NAME, top, stock_daily, log)
- if len(stock_daily['volume']) > 5:
- if stock_daily['bolingerband_lower'][0] is not None and stock_daily['bolingerband_lower'][1] is not None:
- # bb 하단에 부딪힘
- if stock_daily['close'][1] < stock_daily['avg5'][1] and stock_daily['avg5'][0] < stock_daily['close'][0]:
- check = False
- for c in range(1, 4):
- if stock_daily['close'][c] < stock_daily['bolingerband_lower'][c]:
- check = True
- break
- if check:
- dir_code = "17"
- dir_name = "daily_BB하단_내려옴"
- status = str(top) + "_" + status
- final_status_count += 1
- self.writeFile(dir_code, dir_name, CODE, NAME, top, stock_daily, status)
-
- # RSI가 20 이하인 경우, rsi가 rsis위로 올라온 경우
- if len(stock_daily['close']) > 1:
- if stock_daily['rsi'][0] is not None and stock_daily['rsi'][1] is not None and \
- stock_daily['rsis'][0] is not None and stock_daily['rsis'][1] is not None:
- if stock_daily['rsi'][0] <= 20:
- if stock_daily['rsi'][1] < stock_daily['rsis'][1] and stock_daily['rsis'][0] < stock_daily['rsi'][0]:
- dir_code = "18"
- dir_name = "daily_rsi_20이하"
- final_status_count += 1
- status = "{:.2f}".format(stock_daily['rsi'][0]) + "_" + status
- self.writeFile(dir_code, dir_name, CODE, NAME, top, stock_daily, status)
if final_status_count >= 5:
- dir_code = "0"
dir_name = "final"
- self.writeFile(dir_code, dir_name, CODE, NAME, top, stock_daily, final_status, final_status_count)
+ self.writeFile(dir_name, CODE, NAME, top, stock_daily, final_status, final_status_count)
return
diff --git a/stock/analysis/Common.py b/stock/analysis/Common.py
index 55ae629..9d40ecf 100644
--- a/stock/analysis/Common.py
+++ b/stock/analysis/Common.py
@@ -479,4 +479,76 @@ class Common:
rate = round((stock["close"][0] - stock["close"][1]) / stock["close"][1], 2)
if rate <= limit:
return "1d("+str(rate)+")_"
- return ""
\ No newline at end of file
+ return ""
+
+
+ # macd가 n보다 낮은 지 체크
+ def check_macd(self, stock, n=-1000):
+ if stock['macd'][0] <= n:
+ if stock['macd'][1] < stock['macds'][1] and stock['macds'][0] < stock['macds'][0]:
+ return True,
+ return False
+
+ def check_rsi(self, stock, n=10):
+ if stock['macd'][0] <= n:
+ if stock['macd'][1] < stock['macds'][1] and stock['macds'][0] < stock['macds'][0]:
+ return True
+ return False
+
+ # 거래량 체크
+ # 52주 200일 기준 평균 + 50% 보다 높은 거래량의 경우
+ def check_volume(self, stock):
+ c_index = 200
+ if len(stock['volume']) < c_index:
+ c_index = len(stock['volume'])
+ max_volume = max(stock['volume'][1:c_index])
+ if max_volume < stock['volume'][0]:
+ log = "{:.2f}".format((stock['volume'][0] - max_volume)/max_volume)
+ return True, log
+
+ return False, ""
+
+ # 이격도 체크
+ def check_disparity(self, stock):
+ if (98 < stock['disparity_avg5'][0] < 102 and 98 < stock['disparity_avg10'][0] < 102 and 98 < stock['disparity_avg20'][0] < 102 and 98 < stock['disparity_avg60'][0] < 102 and 98 < stock['disparity_avg120'][0] < 102):
+ if stock['close'][1] < stock['avg5'][1] and stock['avg5'][0] < stock['close'][0]:
+ if stock['stochastic_slow_k'][0] < 20:
+ if stock['stochastic_slow_k'][1] < stock['stochastic_slow_d'][1] and stock['stochastic_slow_d'][0] < stock['stochastic_slow_k'][0]:
+ return True
+ return False
+
+ # 낙폭 과대 체크
+ def check_excessive_drop(self, stock):
+ c_index = 52 * 5
+ if len(stock['close']) < c_index:
+ c_index = len(stock['close'])
+ for idx in range(1, c_index):
+ if stock['close'][idx - 1] < int(stock['close'][idx] / 3):
+ c_index = idx
+
+ location = (max(stock['close'][1:c_index]) - stock['close'][0]) / max(
+ stock['close'][1:c_index])
+ if location > 0.6:
+ if stock['stochastic_slow_k'][0] is not None and stock['stochastic_slow_k'][1] is not None and stock['stochastic_slow_d'][1] is not None and stock['stochastic_slow_d'][0] is not None and stock['stochastic_slow_k'][0] is not None:
+ if stock['stochastic_slow_k'][0] < 20 and (stock['stochastic_slow_k'][1] < stock['stochastic_slow_d'][1] and stock['stochastic_slow_d'][0] < stock['stochastic_slow_k'][0]):
+ return True
+ return False
+
+ def check_under_EV_Low(self, stock):
+ if stock['envelope_lower'][0] is not None and stock['envelope_lower'][1] is not None:
+ # ev 하단에 부딪힘
+ if stock['close'][1] < stock['avg5'][1] and stock['avg5'][0] < stock['close'][0]:
+ for c in range(1, 4):
+ if stock['close'][c] < stock['envelope_lower'][c]:
+ return True
+ return False
+
+ def check_under_BB_Low(self, stock):
+ if stock['bolingerband_lower'][0] is not None and stock['bolingerband_lower'][1] is not None:
+ # bb 하단에 부딪힘
+ if stock['close'][1] < stock['avg5'][1] and stock['avg5'][0] < stock['close'][0]:
+ check = False
+ for c in range(1, 4):
+ if stock['close'][c] < stock['bolingerband_lower'][c]:
+ return True
+ return False
\ No newline at end of file