import numpy as np from stock.analysis.MovingAverage import MovingAverage class Common: # 상향 def getDirection(self, data, idx, until=10): up, down = 0, 0 for i in range(idx, idx-(until+1), -1): if data[i - 1] < data[i]: up += 1 if data[i - 1] > data[i]: down += 1 if down < up: if data[idx - 3] < data[idx]: return 'UP' elif up < down: if data[idx - 3] > data[idx]: return 'DOWN' return 'EVEN' # 상향 돌파 def checkUpwardBreakthrough(self, type1, type2, data): if (type1 in data[0] and type1 in data[1] and type1 in data[2] and type2 in data[0] and type2 in data[1] and type2 in data[2]): if ((data[0][type1] < data[1][type1] < data[2][type1]) and (data[0][type1] < data[0][type2] and data[2][type1] > data[2][type2])): return True return False # 하향 돌파 def checkDownwardBreakthrough(self, type1, type2, data): if (type1 in data[0] and type1 in data[1] and type1 in data[2] and type2 in data[0] and type2 in data[1] and type2 in data[2]): if ((data[0][type1] > data[1][type1] > data[2][type1]) and (data[0][type1] > data[0][type2] and data[2][type1] < data[2][type2])): return True return False # YANGBONG # 어제 음봉 이후 장대양봉이었다면, 매수 def checkLongYangBongAfterUmBong(self, stock): if len(stock['close']) > 2: if stock['close'][1] < stock['open'][1]: # 어제가 음봉인지 체크 if stock['open'][0] < stock['close'][0] and stock['close'][0] == stock['high'][0]: # 오늘 장대양봉인지 체크 if stock['volume'][1]*2 < stock['volume'][0]: # 어제 거래량 보다 두배 이상일 때 return "UMYANG_" return "" def checkDoji(self, stock): # 하락 추세이고, 그저께, 어제 음봉이고, 오늘 도지인지 체크한다 if len(stock['close']) > 2: # 하락 추세이고 if stock['close'][1] < stock['close'][2]: # 그저께와 어제가 음봉인지 체크 if stock['close'][2] < stock['open'][2] and stock['close'][1] < stock['open'][1]: # 도지 체크 if stock['open'][0] == stock['close'][0] and stock['low'][0] < stock['close'][0] < stock['high'][0]: return "DOJI_" return "" def checkGravestone(self, stock): # 상승 추세이고, 어제 양봉이고, 오늘 그레이브스톤인지 체크한다 if len(stock['close']) > 2: # 상승 추세이고 if stock['close'][2] < stock['close'][1]: # 어제 양봉인지 체크 if stock['open'][1] < stock['close'][1]: # 오늘 그레이브스톤인지 체크한다 if stock['open'][0] == stock['close'][0] == stock['low'][0] and stock['low'][0] < stock['high'][0]: return "GRAVESTONE_" return "" # 하락 추세에서 드레곤플라이가 나오면 매수 def checkDragonfly(self, stock): # 하락 추세이고, 그저께, 어제 음봉이고, 오늘 드레곤플라이인지 체크한다 if len(stock['close']) > 2: # 하락 추세이고 if stock['close'][1] < stock['close'][1]: # 그저께와 어제가 음봉인지 체크 if stock['close'][2] < stock['open'][2] and stock['close'][1] < stock['open'][1]: # 오늘 드레곤플라이인지 체크한다 if stock['open'][0] == stock['close'][0] == stock['high'][0] and stock['low'][0] < stock['high'][0]: return "DRAGONEFLY_" return "" def checkHammer(self, stock): # 하락 추세이고, 그저께, 어제 음봉이고, 오늘 해머인지 체크한다 if len(stock['close']) > 2: # 하락 추세이고 if stock['close'][1] < stock['close'][1]: # 그저께와 어제가 음봉인지 체크 if stock['close'][2] < stock['open'][2] and stock[1]['close'] < stock[1]['open']: # 오늘 해머인지 체크한다 if stock['open'][0] < stock['close'][0]: if (stock['close'][0] - stock['open'][0]) * 2 < stock['open'][0] - stock['low'][0]: # 윗꼬리가 몸통보다 짧아야 한다. if stock['high'][0] - stock['close'][0] < stock['close'][0] - stock['open'][0]: return "HAMMER_" if stock['close'][0] < stock['open'][0]: if (stock['open'][0] - stock['close'][0]) * 2 < stock['close'][0] - stock['low'][0]: # 윗꼬리가 몸통보다 짧아야 한다. if stock['high'][0] - stock['open'][0] < stock['open'][0] - stock['close'][0]: return "HAMMER_" return "" def checkHangingman(self, stock): # 상승 추세이고, 어제 양봉이고, 오늘 행잉맨인지 체크한다 if len(stock['close']) > 2: # 상승 추세이고 if stock['close'][2] < stock['close'][1]: # 어제 양봉인지 체크 if stock['open'][1] < stock['close'][1]: # 오늘 해머인지 체크한다 if stock['open'][0] < stock['close'][0]: if (stock['close'][0] - stock['open'][0]) * 2 < stock['open'][0] - stock['low'][0]: # 윗꼬리가 몸통보다 짧아야 한다. if stock['high'][0] - stock['close'][0] < stock['close'][0] - stock['open'][0]: return "HANGINGMAN_" if stock['close'][0] < stock['open'][0]: if (stock['open'][0] - stock['close'][0]) * 2 < stock['close'][0] - stock['low'][0]: # 윗꼬리가 몸통보다 짧아야 한다. if stock['high'][0] - stock['open'][0] < stock['open'][0] - stock['close'][0]: return "HANGINGMAN_" return "" def checkEngulfingHigh(self, stock): # 하락 추세에서 상승 장악형인지 체크 if len(stock['close']) > 2: # 하락 추세이고 if stock['close'][1] < stock['close'][2]: # 그저께와 어제가 음봉인지 체크 if stock['close'][2] < stock['open'][2] and stock['close'][1] < stock['open'][1]: # 오늘 상승장악형인지 체크 if stock['open'][0] < stock['close'][0]: if stock['open'][1] < stock['close'][0] and stock['open'][0] < stock['close'][1]: return "ENHIGH_" return "" def checkEngulfingLow(self, stock): # 상승 추세에서 하락 장악형인지 체크 if len(stock['close']) > 2: # 상승 추세이고 if stock['close'][2] < stock['close'][1]: # 어제 양봉인지 체크 if stock['open'][1] < stock['close'][1]: # 오늘 하락장악형인지 체크 if stock['close'][0] < stock['open'][0]: if stock['close'][1] < stock['open'][0] and stock['close'][0] < stock['open'][1]: return "ENLOW_" return "" def checkHaramiHigh(self, stock): # # 하락 추세에서 상승포아형인지 체크 if len(stock['close']) > 2: # 하락 추세이고 if stock['close'][1] < stock['close'][2]: # 그저께와 어제가 음봉인지 체크 if stock['close'][2] < stock['open'][2] and stock['close'][1] < stock['open'][1]: # 오늘 상승포아형인지 체크 if stock['open'][0] < stock['close'][0]: if stock['close'][1] < stock['low'][0] and stock['high'][0] < stock['open'][1]: return "HAHIGH_" return "" def checkHaramiLow(self, stock): # 상승 추세에서 하락 포아형인지 체크 if len(stock['close']) > 2: # 상승 추세이고 if stock['close'][2] < stock['close'][1]: # 어제 양봉인지 체크 if stock['open'][1] < stock['close'][1]: # 오늘 하락포아형인지 체크 if stock['close'][0] < stock['open'][0]: if stock['open'][1] < stock['low'][0] and stock['high'][0] < stock['close'][1]: return "HALOW_" return "" def checkPiercing(self, stock): # 하락 추세에서 관통형인지 체크 if len(stock['close']) > 2: # 하락 추세이고 if stock['close'][1] < stock['close'][2]: # 그저께와 어제가 음봉인지 체크 if stock['close'][2] < stock['open'][2] and stock['close'][1] < stock['open'][1]: # 오늘 관통형인지 체크 if stock['open'][0] < stock['close'][0]: if stock['open'][0] < stock['low'][1] and (stock['close'][1] + stock['open'][1])/2 < stock['close'][0] < stock['close'][1]: return "PIERCING_" return "" def checkDarkCloud(self, stock): # 상승 추세에서 흑운형인지 체크 if len(stock['close']) > 2: # 상승 추세이고 if stock['close'][2] < stock['close'][1]: # 어제 양봉인지 체크 if stock['open'][1] < stock['close'][1]: # 오늘 흑운형인지 체크 if stock['close'][0] < stock['open'][0]: if stock['high'][1] < stock['open'][0] and stock['open'][1] < stock['close'][0] < (stock['open'][1] + stock['close'][1])/2: return "DARKCLOUD_" return "" def checkMorningstar(self, stock): # 하락 추세에서 샛별인지 체크 if len(stock['close']) > 2: # 하락 추세이고 if stock['close'][1] < stock['close'][2]: # 그저께와 어제가 음봉인지 체크 if stock['close'][2] < stock['open'][2] and stock['close'][1] < stock['open'][1]: # 오늘 샛별인지 체크 # 어제 갭 체크 if stock['open'][1] < stock['close'][2] and stock['close'][1] < stock['close'][2]: # 오늘 시가가 어제 종가보다 높으며 양봉 if stock['close'][1] < stock['open'][0] < stock['close'][0]: return "MORNINGSTAR_" return "" def checkEveningstar(self, stock): # 상승 추세에서 저녁별형인지 체크 if len(stock['close']) > 2: # 상승 추세이고 if stock['close'][2] < stock['close'][1]: # 어제 양봉인지 체크 if stock['open'][1] < stock['close'][1]: # 오늘 저녁별형인지 체크 # 어제 갭 체크 if stock['close'][2] < stock['open'][1] and stock['close'][2] < stock['close'][1]: # 오늘 시가가 어제 종가보다 낮으며 음봉 if stock['close'][0] < stock['open'][1] < stock['close'][1]: return "EVENINGSTAR_" return "" def checkAllUpperCross(self, stock): if len(stock['close']) > 10: if stock['avg5'][0] < stock['close'][0] and stock['avg20'][0] < stock['close'][0] and stock['avg60'][0] < stock['close'][0] and stock['avg120'][0] < stock['close'][0]: for j in range(1, 6): if stock['close'][j] < stock['avg5'][j] and stock['close'][j] < stock['avg20'][j] and stock['close'][j] < stock['avg60'][j] and stock['close'][j] < stock['avg120'][j]: return "ALLUPPER_" return "" def check_golded_cross(self, stock): if len(stock['close']) > 1: # 60 -> 120 # 오늘 지수는 120 < 60 < 20 < 5 # 어제 지수는 60 < 120 이었다. # 60, 20, 5일선 모두 어제 보다 오늘이 더 높다 (상승중) # 5일과 20일선은 상승 중이며, 60일선이 120일 선을 뚫고 올라온 순간인지 체크함 (삼성전자 2021-07-29) # 이때 바로 매수하지 않는다. # 이 시점 이후로 5일선이 20일선을 하방으로 뚫었다가 다시 20일선을 상방으로 뚫는 순간 매수를 시도한다. if stock['avg120'][0] < stock['avg60'][0] < stock['avg20'][0] < stock['avg5'][0]: if stock['avg120'][1] > stock['avg60'][1]: if (stock['avg60'][1] < stock['avg60'][0] and stock['avg20'][1] < stock['avg20'][0] and stock['avg5'][1] < stock['avg5'][0]): return "GOLDEN#1_" # 20 -> 120: 5일과 20일, 60일선은 상승 중이며, 20일선이 120일 선을 뚫고 올라온 순간인지 체크 (SK 2021-12-09, 나노스 2021-02-04) # 어제는 60일선 < 20일선 < 120일선 < 5일선이지만, 오늘은 60일선 < 120일선 < 20일선 < 5일선 # 이때 바로 매수하지 않는다. # 이 시점 이후로 5일선이 20일선을 하방으로 뚫었다가 다시 20일선을 상방으로 뚫는 순간 매수를 시도한다. if stock['avg60'][0] < stock['avg120'][0] < stock['avg20'][0] < stock['avg5'][0]: if stock['avg60'][1] < stock['avg20'][1] < stock['avg120'][0] < stock['avg5'][0]: if (stock['avg60'][1] < stock['avg60'][0] and stock['avg20'][1] < stock['avg20'][0] and stock['avg5'][1] < stock['avg5'][0]): return "GOLDEN#2_" # 20 -> 120: 5일과 20일, 60일선은 상승 중이며, 20일선이 120일 선을 뚫고 올라온 순간인지 체크 (갤럭시아머니트리 2021-02-08) # 어제는 60일선 < 120일선 < 5일선 < 20일선이지만, 오늘은 60일선 < 120일선 < 20일선 < 5일선 if stock['avg60'][0] < stock['avg120'][0] < stock['avg20'][0] < stock['avg5'][0]: if stock['avg60'][1] < stock['avg20'][1] < stock['avg120'][0] < stock['avg5'][0]: if (stock['avg60'][1] < stock['avg60'][0] and stock['avg20'][1] < stock['avg20'][0] and stock['avg5'][1] < stock['avg5'][0]): return "GOLDEN#3_" return "" def check_bearmarket_buying(self, stock): if len(stock['close']) > 1: # 5일선 상승 시점 확인 (SK 2020년 3월 24일) # 어제는 5일선 < 20일선 < 120일선 < 60일선이며, 오늘은 20일선 < 120일선 < 60일선 # 어제와 오늘 모두 20일, 60일, 120일선은 모두 하락이다. # 어제 종가보다 오늘 종가가 높고, 종가는 5일선 위에 올라왔다. # 오늘 slow_k는 30 이하이며, 어제는 slow_d가 높았지만, 오늘은 slow_k가 더 높음 if (stock['avg5'][1] < stock['avg20'][1] < stock['avg120'][1] < stock['avg60'][0]) and (stock['avg20'][0] < stock['avg120'][1] < stock['avg60'][0]): if stock['avg120'][0] < stock['avg120'][1] and stock['avg60'][0] < stock['avg60'][1] and stock['avg20'][0] < stock['avg20'][1]: if stock['close'][1] <= stock['close'][0] and stock['avg5'][0] <= stock['close'][0]: if (stock['stochastic_slow_k'][0] < 30 and (stock['stochastic_slow_k'][1] < stock['stochastic_slow_d'][1] and stock['stochastic_slow_d'][0] < stock['stochastic_slow_k'][0])): return "BEARMARKET#1_" # 5일선 상승 시점 확인 (원풍물산 2020년 3월 24일, NHN한국사이버결제 2018년 11월 2일) # 어제는 5일선 < 20일선 < 60일선 < 120일선이며, 오늘은 20일선 < 60일선 < 120일선 # 어제와 오늘 모두 20일, 60일, 120일선은 모두 하락이다. # 어제 종가보다 오늘 종가가 높고, 종가는 5일선 위에 올라왔다. # 오늘 slow_k는 30 이하이며, 어제는 slow_d가 높았지만, 오늘은 slow_k가 더 높음 if (stock['avg5'][1] < stock['avg20'][1] < stock['avg60'][1] < stock['avg120'][0]) and (stock['avg20'][0] < stock['avg60'][1] < stock['avg120'][0]): if stock['avg120'][0] < stock['avg120'][1] and stock['avg60'][0] < stock['avg60'][1] and stock['avg20'][0] < stock['avg20'][1]: if stock['close'][1] <= stock['close'][0] and stock['avg5'][0] <= stock['close'][0]: if (stock['stochastic_slow_k'][0] < 30 and (stock['stochastic_slow_k'][1] < stock['stochastic_slow_d'][1] and stock['stochastic_slow_d'][0] < stock['stochastic_slow_k'][0])): return "BEARMARKET#2_" return "" def check_stochastic(self, stock): if len(stock['close']) > 60: # 스토케스틱이 15 이하인 경우 # 어제보다 slow_k가 상승했고, 오늘 slow_k가 slow_d 위에 있는 경우, if stock['stochastic_slow_k'][0] is not None and stock['stochastic_slow_k'][0] < 15: if stock['stochastic_slow_k'][1] < stock['stochastic_slow_k'][0] and stock['stochastic_slow_d'][0] < stock['stochastic_slow_k'][0]: return "STOCHASTIC_" return "" def check_stochastic_buying(self, stock, stochastic, ichimoku, i): if len(stock['close']) > 60: # 삼성전자 2020년 11월 4일 # 어제는 slow_K가 Slow_d 아래였지만, 오늘은 slow_K가 Slow_d 보다 높다. # 에제의 slow_k는 20보다 작고, 오늘의 slow_K는 30보다 작다 # 1일전이나, 2, 3일전의 종가가 일목균형표 내의 선행스팬1 아래 존재하며,오늘 고가는 선행스팬1 위에 존재한다. # 그저께 시가보다 어제의 시가가, 어제의 시가보다는 오늘의 시가가 높다. if (stochastic[i-1]['slow_k'] < stochastic[i-1]['slow_d'] and stochastic[i]['slow_d'] < stochastic[i]['slow_k']): if (stochastic[i - 1]['slow_k'] < 20 and stochastic[i]['slow_k'] < 30): if ((stock[i-3]['close'] < ichimoku[i-3]['leadingSpan1'] or stock[i-2]['close'] < ichimoku[i-2]['leadingSpan1'] or stock[i-1]['close'] < ichimoku[i-1]['leadingSpan1']) and ichimoku[i-1]['leadingSpan1'] < stock[i-1]['high']): if stock[i-2]['open'] < stock[i-1]['open'] < stock[i]['open']: return "STOCHASTIC#1_" # 스토케스틱이 15 이하인 경우 # 어제보다 slow_k가 상승했고, 오늘 slow_k가 slow_d 위에 있는 경우, # 오늘 종가가 5일선 위에 있는 경우 if stochastic[i]['slow_k'] < 15: if stochastic[i - 1]['slow_k'] < stochastic[i]['slow_k'] and stochastic[i]['slow_d'] < stochastic[i]['slow_k']: if stock[i]['avg5'] < stock[i]['close']: return "STOCHASTIC#2_" return "" def check_Dolpa(self, stock, i, avg1, avg2): upper_index = 0 if len(stock['close']) > 2: if stock[i-1]["avg"+avg1] < stock[i-1]["avg"+avg2] and stock[i]["avg"+avg1] > stock[i]["avg"+avg2]: return avg1+"_"+avg2+"_" return "" def check_Dolpa_Jiji(self, stock, day='20'): upper_index = 0 if len(stock['close']) > 5: for idx in range(1, 5): # day선을 돌파하는 양봉이고, 종가가 최고가 보다 100 이내이어야 한다. if stock['open'][idx] < stock["avg"+day][idx] < stock['close'][idx] and stock['high'][idx] - 100 <= stock['close'][idx]: upper_index = idx break if upper_index != 0: for cidx in range(1, upper_index): # 해당일의 종가보다 현재의 시가가 높거나 같아야 하며, 현재가는 양봉이어야 한다. if stock['close'][upper_index] <= stock['open'][cidx] and stock['open'][cidx] < stock['close'][cidx]: # 해당 기준일 선은 상승이어야 한다. if stock['avg'+day][upper_index] < stock['avg'+day][cidx]: return day + "_" return "" def check_Dolpa_Jiji_20(self, stock): """ top: 이전 5일선이 20일선 위에 있을 때 최고가 top일 체크 사항 (20일 < 5일선) 5일선이 20일 선으로 내려왔다가 다시 20일선 위로 올라왔고, top < 오늘 시가 + 100 top < 시가 < 종가 라면 다음날 매수한다. # https://docs.google.com/presentation/d/1MVuaeRNljqLCdn4dPZmvVdtl2Ab09Zwg/edit#slide=id.gc7b796e645_0_80 """ if len(stock['close']) > 61: if stock['avg20'][0] < stock['close'][0] and stock['avg20'][0] < stock['open'][0]: if stock['avg5'][0] < stock['avg20'][0]: index1 = -1 for j in range(1, 61): if stock['avg20'][j] < stock['avg5'][j]: index1 = j break top = 0 for j in range(index1+1, 61): if stock['open'][j] < stock['close'][j]: if top < stock['close'][j]: top = stock['close'][j] else: if top < stock['open'][j]: top = stock['open'][j] if stock['avg5'][j] < stock['avg20'][j]: break return "5-20_" return "" def check_Danta1(self, stock): """ 어제 상한가 혹은 상승양봉이 나온다. 오늘 상승 출발을 해야 하며 상승 음봉이 나온다 - 어제 종가 = 어제 상한가 < 종가 < 시가 < 상한가 https://docs.google.com/presentation/d/1MVuaeRNljqLCdn4dPZmvVdtl2Ab09Zwg/edit#slide=id.gc7b796e645_0_109 만약 다음날 시작초가가 오늘 종가보다 높게 상승으로 출발한다면 매수를 한다. 손절가는 오늘 최저가이다. """ if stock['open'][1] < stock['close'][1] == stock['high'][1]: if stock['close'][1] < stock['close'][0] < stock['open'][0] < stock['high'][0]: return "danta1_" return "" def check_Danta2(self, stock): """ 쐐기, 수렴, 깃대 패턴 확인 # https://docs.google.com/presentation/d/1MVuaeRNljqLCdn4dPZmvVdtl2Ab09Zwg/edit#slide=id.gc7b796e645_0_144 상단 추세선을 돌파하면 매수를 한다. """ price_10 = round(stock["close"][0] / 10) if stock["open"][0] < stock["close"][0]: top = stock["close"][0] bottom = stock["open"][0] else: top = stock["open"][0] bottom = stock["close"][0] if len(stock) > 21: for i in range(2, 21): if stock["open"][i] < stock["close"][i]: if top < stock["close"][i]: top = stock["close"][i] if stock["open"][i] < bottom: bottom = stock["open"][i] else: if top < stock["open"][i]: top = stock["open"][i] if stock["close"][i] < bottom: bottom = stock["close"][i] if top - bottom < price_10: return "danta2_" return "" def check_RightArrange(self, stock): """ 어제는 정배열이 아니었는데, 오늘은 정배열인 경우 """ if len(stock['close']) > 2: if (not (stock["avg120"][1] < stock["avg60"][1] < stock["avg20"][1] < stock["avg5"][1] < stock["close"][1]) and stock["avg120"][0] < stock["avg60"][0] < stock["avg20"][0] < stock["avg5"][0] < stock["close"][0]): if stock["avg5"][1] < stock["avg5"][0]: return "arrange_" return "" def checkHigherUmbong(self, stock): # 음봉인데 어제보다 종가가 더 높은 경우 # 이 경우 정배열 상태인지도 함께 체크를 한다. if len(stock['close']) > 3: # 어제는 거래량이 터진 양봉이다. if stock['open'][1] < stock['close'][1] and 5*stock['volume'][2] < stock['volume'][1]: # 오늘은 음봉인데, 오늘 종가는 어제 시가보다는 높다 if stock['close'][0] < stock['open'][0] and stock['open'][1] < stock['close'][0]: return "HIGHERUMBONG_" return "" def check_W1Rise(self, stock, limit): if len(stock['close']) > 5: rate = round((stock["close"][0] - stock["close"][4]) / stock["close"][4],2) if rate >= limit: return "1w("+str(rate)+")_" return "" def check_D1Fall(self, stock, limit): if len(stock['close']) > 2: # 1000, 900, (900 - 1000) / 900 = -0.111 # 1000, 800, (800 - 1000) / 800 = -0.25 rate = round((stock["close"][0] - stock["close"][1]) / stock["close"][1], 2) if rate <= limit: return "1d("+str(rate)+")_" 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 def check_env_lower_rsi(self, stock): if stock['close'][1] < stock['envelope_lower'][1] and stock['envelope_lower'][0] < stock['close'][0]: if stock['rsi'][0] < 50: return True return False def check_env_upper(self, stock): if stock['close'][1] < stock['envelope_upper'][1] and stock['envelope_upper'][0] < stock['close'][0]: return True return False def check_env_upper_volume(self, stock): c_index = 200 check = True max_volume = max(stock['volume'][1:c_index + 1]) if 0 < max_volume < stock['volume'][0] and stock['close'][1] < stock['close'][0]: check = True c_index = 20 sum_volume = sum(stock['volume'][1:c_index + 1]) avg_volume = sum_volume / c_index if (avg_volume * 5) < stock['volume'][0] and stock['close'][1] < stock['close'][0]: check = True if check and stock['close'][1] < stock['envelope_upper'][1] and stock['envelope_upper'][0] < stock['close'][0]: return True return False # 거래량 체크 # 52주 200일 기준 평균 + 50% 보다 높은 거래량의 경우 def check_volume(self, stock): c_index = 200 max_volume = max(stock['volume'][1:c_index+1]) if 0 < max_volume < stock['volume'][0] and stock['close'][1] < stock['close'][0]: log = "{:.2f}".format(stock['volume'][0]/max_volume) return True, log c_index = 20 sum_volume = sum(stock['volume'][1:c_index + 1]) avg_volume = sum_volume / c_index if (avg_volume * 5) < stock['volume'][0] and stock['close'][1] < stock['close'][0]: log = "{:.2f}".format(stock['volume'][0]/max_volume) return True, log return False, "" # 이격도 체크 def check_disparity(self, stock, type="daily"): if (99 < stock['disparity_avg5'][0] < 101 and 98.7 < stock['disparity_avg10'][0] < 101.3 and 98.5 < stock['disparity_avg20'][0] < 101.5 and 98.3 < stock['disparity_avg60'][0] < 101.7 and 98 < stock['disparity_avg120'][0] < 102): return True return False # 종가가 5일선_돌파 def check_5_moving_line(self, stock): if (stock['close'][1] < stock['avg5'][1] and stock['avg5'][0] < stock['close'][0]): if stock['volume'][1] < stock['volume'][0]: if stock['open'][0] < stock['close'][0]: return True return False # 5일선이 20일선_돌파 def check_5__20_moving_line(self, stock): if (stock['avg5'][1] < stock['avg20'][1] and stock['avg20'][0] < stock['avg5'][0]): if stock['volume'][1] < stock['volume'][0]: if stock['open'][0] < stock['close'][0]: return True return False # 20일선이 60일선_돌파 def check_20__60_moving_line(self, stock): if (stock['avg20'][1] < stock['avg60'][1] and stock['avg60'][0] < stock['avg20'][0]): if stock['volume'][1] < stock['volume'][0]: if stock['open'][0] < stock['close'][0]: return True return False def check_optimal_buy_timeing(self, param, stock): check = False if len(stock['trend']) < 1: return check rise_rate = param['bull'][0] / (param['bull'][0]+param['bear'][0]+param['bull'][0]) if ( (stock['macd'][1] < stock['macd'][0] and stock['rsi'][0] < 80) or (stock['rsi'][1] < stock['rsi'][0] and np.min(stock['rsi'][:3]) < 35) or (stock['rsi'][0] < 35) or 0.7 <= rise_rate ): # avg300 상승 if stock['avg300'][1] < stock['avg300'][0]: # avg5 < trend if stock['avg5'][0] < stock['trend'][0]: # avg5 이전 3개 봉 위 if np.max(stock['avg5'][:3]) < stock['avg5'][0]: buy_type = "trend" check = True # 상승 추세일 때 if (stock['macd'][1] < stock['macd'][0] and stock['macds'][0] < stock['macd'][0] or stock['rsi'][1] < stock['rsi'][0]): # rsi가 50을 상향 돌파할 때 if 0.9 <= rise_rate and np.max(stock['rsi'][:5]) < 50 and 50 < stock['rsi'][0]: buy_type = "rsi" check = True # golden & 거래량 if stock['avg120'][0] < stock['avg60'][0] < stock['avg20'][0] < stock['avg5'][0]: buy_type = "golden" check = True # rsi가 30보다 작은 후에 상승일 때 if np.min(stock['rsi'][:5]) < 30: if stock['rsi'][1] < stock['rsi'][0]: buy_type = "rsi" check = True if not(stock['rsi'][1] < stock['rsi'][0] and stock['rsis'][0] < stock['rsi'][0]): check = False return check def buy_stock_candidate(self, param, stock): check = False if len(stock['trend']) < 1: return check if not (stock['avg60'][1] < stock['avg20'][1] and stock['avg5'][1]) and (stock['avg60'][0] < stock['avg20'][0] and stock['avg5'][0]): if stock['upper'][0] < stock['avg5'][0]: check = True return check # 낙폭 과대 체크 def check_excessive_drop(self, stock): c_index = 200 if len(stock['close']) > c_index: max_value = max(stock['close'][1:c_index+1]) if max_value * 0.4 < stock['close'][0] < max_value * 0.6: return True, "{:.2f}".format(stock['close'][0]/max_value) 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'][0] < stock['envelope_lower'][0]: return True return False def check_under_BB_Low(self, stock): if stock['lower'][0] is not None and stock['lower'][1] is not None: # bb 하단에 부딪힘 if stock['close'][0] < stock['lower'][0]: return True return False # OBV (최저점에서 누적 거래량) 체크 def check_obv(self, stock): lowest_index = -1 p_price = 99999999999999 size = len(stock['close']) for i in range(size): if stock['low'][i] < p_price: p_price = stock['low'][i] lowest_index = i if lowest_index > 600: lowest_index = 600 obv = 0 obvs = [] for i in range(lowest_index, -1, -1): if stock['open'][i] < stock['close'][i]: obv += stock['volume'][i] elif stock['close'][i] < stock['open'][i]: obv -= stock['volume'][i] obvs.append(obv) q_5 = MovingAverage(5) q_20 = MovingAverage(20) q_60 = MovingAverage(60) if len(obvs) > 60: for i in range(len(obvs)): q_5.enqueue(obvs[i]) q_20.enqueue(obvs[i]) q_60.enqueue(obvs[i]) stock['obv5'].append( q_5.avg() ) stock['obv20'].append( q_20.avg() ) stock['obv60'].append( q_60.avg() ) lowest_index -= 1 stock['obv5'] = list(reversed(stock['obv5'])) stock['obv20'] = list(reversed(stock['obv20'])) stock['obv60'] = list(reversed(stock['obv60'])) obvs = list(reversed(obvs)) if len(obvs) > 60 and obv > 0: return obv return -1