905 lines
40 KiB
Python
905 lines
40 KiB
Python
import pandas as pd
|
|
|
|
from datetime import datetime
|
|
from stock.analysis.Common import Common
|
|
from stock.analysis.Stochastic import Stochastic
|
|
from stock.analysis.RSI import RSI
|
|
from stock.analysis.MACD import MACD
|
|
from stock.analysis.IchimokuCloud import IchimokuCloud
|
|
|
|
|
|
class BuySellChecker:
|
|
common = None
|
|
stochastic = None
|
|
rsi = None
|
|
macd = None
|
|
ichimokuCloud = None
|
|
|
|
BUY_COUNT = None
|
|
|
|
def __init__(self):
|
|
self.common = Common()
|
|
self.stochastic = Stochastic()
|
|
self.rsi = RSI()
|
|
self.macd = MACD()
|
|
self.ichimokuCloud = IchimokuCloud()
|
|
|
|
self.BUY_COUNT = 0
|
|
|
|
return
|
|
|
|
def isYangbong(self, data, i):
|
|
if data['close'][i] > data['open'][i]:
|
|
return True
|
|
else:
|
|
if data['low'][i] < data['close'][i] == data['open'][i] == data['high'][i]:
|
|
return True
|
|
if data['low'][i] < data['open'][i] == data['close'][i] < data['high'][i]:
|
|
return True
|
|
return False
|
|
|
|
def isUmbong(self, data, i):
|
|
if data['close'][i] < data['open'][i]:
|
|
return True
|
|
else:
|
|
if data['low'][i] == data['close'][i] == data['open'][i] < data['high'][i]:
|
|
return True
|
|
if data['low'][i] < data['open'][i] == data['close'][i] < data['high'][i]:
|
|
return True
|
|
return False
|
|
|
|
# 지난 1시간 30분 동안 12분 선이 20분 선위에 20분 이상 있었는지 체크
|
|
def check_12_over_20_for_30(self, data, i, default=90):
|
|
if i - default < 381:
|
|
return False
|
|
|
|
check_12_over_20_for_30 = False
|
|
for c in range(i - default, i - 20):
|
|
if data['avg20'][c] < data['avg20'][i]:
|
|
value = [1 if data['avg20'][d] < data['avg12'][d] else 0 for d in range(c, c + 20)]
|
|
if len(value) == 20 and sum(value) == 20:
|
|
check_12_over_20_for_30 = True
|
|
break
|
|
return check_12_over_20_for_30
|
|
|
|
# 지난 1시간 동안 3, 6, 9, 12분 선이 10분 이상 20분 선 아래 있었는지 체크
|
|
def check_under_20_for_10(self, data, i, within=60, during=10):
|
|
if i - within < 381:
|
|
return False
|
|
|
|
check_under_20_for_10 = False
|
|
for c in range(i - within, i - during):
|
|
value = [
|
|
1 if max(data['avg3'][d], data['avg6'][d], data['avg9'][d], data['avg12'][d]) < data['avg20'][d] else 0
|
|
for d in range(c, c + during)]
|
|
if len(value) == during and sum(value) == during:
|
|
check_under_20_for_10 = True
|
|
break
|
|
return check_under_20_for_10
|
|
|
|
def max_min_avg(self, data, i):
|
|
return max(data['avg3'][i], data['avg6'][i], data['avg9'][i], data['avg12'][i], data['avg20'][i]) - min(
|
|
data['avg3'][i], data['avg6'][i], data['avg9'][i], data['avg12'][i], data['avg20'][i])
|
|
|
|
def check_inverse_arrangement_before(self, data, i, within=30, during=5):
|
|
if i - within < 381:
|
|
return False
|
|
|
|
inverse_arrangement = False
|
|
for c in range(i - within, i - during):
|
|
value = [
|
|
1 if data['avg3'][d] < data['avg6'][d] < data['avg9'][d] < data['avg12'][d] < data['avg20'][d] else 0
|
|
for d in range(c, c + during)]
|
|
if len(value) == during and sum(value) == during - 1:
|
|
inverse_arrangement = True
|
|
break
|
|
return inverse_arrangement
|
|
|
|
def checkUpDirection(self, data, i):
|
|
# 0: 무추세, -1: 하락 추세, 1: 상승 추세
|
|
close = data['close'][i]
|
|
# up_count = sum([1 if data['high'][c] < close else 0 for c in range(i-20, i)])
|
|
# down_count = sum([1 if close < data['low'][c] else 0 for c in range(i - 20, i)])
|
|
|
|
lagging_change = sum([1 if data['laggingSpan'][c] < data['changeLine'][c] else 0 for c in range(i - 20, i)])
|
|
change_lagging = sum([1 if data['laggingSpan'][c] > data['changeLine'][c] else 0 for c in range(i - 20, i)])
|
|
|
|
if lagging_change > 10:
|
|
return 1
|
|
if change_lagging == 20:
|
|
return -1
|
|
return 0
|
|
|
|
def isAvg200UP(self, data, idx, until=10, limit=0.9):
|
|
even, up, down = 0, 0, 0
|
|
for i in range(idx, idx - (until + 1), -1):
|
|
if data['avg200'][i] < data['close'][i]:
|
|
up += 1
|
|
if data['avg200'][i] > data['close'][i]:
|
|
down += 1
|
|
else:
|
|
even += 1
|
|
if up * (1 - limit) > down:
|
|
return True
|
|
return False
|
|
|
|
|
|
def getBuyPriceAndWeight_122630(self, i, data):
|
|
buy, weight = -1, -1
|
|
|
|
if i > 200:
|
|
if (
|
|
(
|
|
min(data['avg200'][i-53: i-48]) > min(data['avg200'][i-48: i-43]) >
|
|
min(data['avg200'][i-43: i-38]) > min(data['avg200'][i-38: i-33]) >
|
|
min(data['avg200'][i-33: i-28]) > min(data['avg200'][i-28: i-23]) >
|
|
min(data['avg200'][i-23: i-18]) > min(data['avg200'][i-18: i-13]) >
|
|
min(data['avg200'][i-13: i-8]) > min(data['avg200'][i-8: i-3]) >
|
|
data['avg200'][i-3]
|
|
) and
|
|
data['avg200'][i-3] < min(data['avg200'][i-2:i])
|
|
):
|
|
if data['close'][i] < data['close'][i-30]:
|
|
buy = data['close'][i]
|
|
weight = 0.2
|
|
|
|
if (
|
|
(
|
|
min(data['avg200'][i-103: i-93]) >= min(data['avg200'][i-93: i-83]) >=
|
|
min(data['avg200'][i-83: i-73]) >= min(data['avg200'][i-73: i-63]) >=
|
|
min(data['avg200'][i-63: i-53]) >= min(data['avg200'][i-53: i-43]) >=
|
|
min(data['avg200'][i-43: i-33]) >= min(data['avg200'][i-33: i-23]) >
|
|
min(data['avg200'][i-23: i-13]) > min(data['avg200'][i-13: i-3]) >
|
|
data['avg200'][i-3]
|
|
) and
|
|
(
|
|
max(data['avg200'][i - 103: i - 93]) - min(data['avg200'][i - 93: i - 83]) >
|
|
max(data['avg200'][i - 83: i - 73]) - min(data['avg200'][i - 73: i - 63]) >
|
|
max(data['avg200'][i - 63: i - 53]) - min(data['avg200'][i - 53: i - 43]) >
|
|
max(data['avg200'][i - 43: i - 33]) - min(data['avg200'][i - 33: i - 23]) >
|
|
max(data['avg200'][i - 23: i - 13]) - min(data['avg200'][i - 13: i - 3])
|
|
) and
|
|
data['avg200'][i-3] < min(data['avg200'][i-2:i])
|
|
):
|
|
if 25 < max(data['macd'][i-50: i-20]) and data['close'][i] < data['close'][i - 30]:
|
|
if data['slow_k'][i - 1] < data['slow_k'][i] and data['slow_k'][i] < 50 and data['macd'][i-1] < data['macd'][i]:
|
|
buy = data['close'][i]
|
|
weight = 0.2
|
|
|
|
if 25 < max(data['macd'][i-50: i-20]) and min(data['macd'][i-20: i]) < -30 and 0 < data['macd'][i] < 3:
|
|
if data['slow_k'][i - 1] < data['slow_k'][i] and data['slow_k'][i] < 50 and data['macd'][i-1] < data['macd'][i]:
|
|
buy = data['close'][i]+5
|
|
weight = 0.2
|
|
|
|
if 25 < max(data['macd'][i-50: i-20]) and data['macd'][i] < -20 and data['macd'][i-1] < data['macd'][i]:
|
|
if data['slow_k'][i - 1] < data['slow_k'][i] and data['slow_k'][i] < 50 and data['macd'][i-1] < data['macd'][i]:
|
|
buy = data['close'][i]+5
|
|
weight = 0.2
|
|
|
|
if 0.00988 < data['disparity_avg5'][i] - data['disparity_avg200'][i]:
|
|
if 25 < max(data['macd'][i-50: i-20]) and data['slow_k'][i - 1] < data['slow_k'][i] and data['slow_k'][i] < 50 and data['macd'][i-1] < data['macd'][i]:
|
|
buy = data['close'][i] + 10
|
|
weight = 0.2
|
|
return buy, weight
|
|
|
|
|
|
def getBuyPriceAndWeight_252670(self, i, data):
|
|
buy, weight = -1, -1
|
|
|
|
if i > 50:
|
|
up, down = 0, 0
|
|
for idx in range(i, i - (300 + 1), -1):
|
|
if data['avg200'][idx-1] < data['avg200'][idx]:
|
|
up += 1
|
|
if data['avg200'][idx-1] > data['avg200'][idx]:
|
|
down += 1
|
|
if up < down:
|
|
if max(data['avg200'][i-20:i])+0.05 < data['avg200'][i]:
|
|
buy = data['close'][i]
|
|
weight = 0.3
|
|
|
|
up, down = 0, 0
|
|
for idx in range(i, i - (10 + 1), -1):
|
|
if data['close'][idx-1] < data['close'][idx]:
|
|
up += 1
|
|
elif data['close'][idx - 1] > data['close'][idx]:
|
|
down += 1
|
|
if down < up:
|
|
buy, weight = -1, -1
|
|
|
|
if data['close'][i] < data['avg200'][i] or data['avg200'][i] + 10 < data['close'][i]:
|
|
buy, weight = -1, -1
|
|
|
|
if 2 < data['macd'][i]:
|
|
buy, weight = -1, -1
|
|
|
|
return buy, weight
|
|
|
|
def getBuyPriceAndWeight(self, stock_code, i, data):
|
|
buy, weight = -1, -1
|
|
|
|
if i > 50:
|
|
|
|
if stock_code == '233740':
|
|
if data['macd'][i-2] < 0 and 0 < data['macd'][i-1] and 0 < data['macd'][i]:
|
|
if data['volume'][i - 2] < data['volume'][i - 1] < data['volume'][i]:
|
|
if min(data['macd'][i-30:i].tolist()) < -50:
|
|
buy, weight = data['close'][i], 1
|
|
|
|
if min(data['macd'][i-5:i].tolist()) < min(data['macd'][i-15:i-10].tolist()) < -50:
|
|
if -50 < max(data['macd'][i-15:i-7].tolist()):
|
|
buy, weight = data['close'][i], 1
|
|
|
|
elif stock_code == '122630':
|
|
if data['macd'][i - 2] < 0 and 0 < data['macd'][i - 1] and 0 < data['macd'][i]:
|
|
if data['volume'][i - 2] < data['volume'][i - 1] < data['volume'][i]:
|
|
if min(data['macd'][i - 30:i].tolist()) < -25:
|
|
buy, weight = data['close'][i], 1
|
|
|
|
if min(data['macd'][i-5:i].tolist()) < min(data['macd'][i - 15:i - 10].tolist()) < -30:
|
|
if -20 < max(data['macd'][i - 15:i - 7].tolist()):
|
|
buy, weight = data['close'][i], 1
|
|
|
|
|
|
elif stock_code == '252670':
|
|
if min(data['macd'][i - 40:i - 20].tolist()) < -5 < data['macd'][i]:
|
|
if data['close'][i] < min(data['close'][i - 40:i - 20].tolist()):
|
|
buy, weight = data['close'][i], 1
|
|
elif stock_code == '251340':
|
|
if min(data['macd'][i-40:i-20].tolist()) < -20 < data['macd'][i]:
|
|
if data['close'][i] < min(data['close'][i-40:i-20].tolist()):
|
|
buy, weight = data['close'][i], 1
|
|
|
|
return buy, weight
|
|
|
|
def getSellPriceAndWeight(self, stock_code, i, data):
|
|
sell, weight = -1, -1
|
|
|
|
# 1) 스토캐스틱 과매수
|
|
slow_k_sell = False
|
|
for idx in range(i, i-10, -1):
|
|
if data['slow_k'][idx] > 80:
|
|
slow_k_sell = True
|
|
break
|
|
|
|
# 2) macd 교차 신호
|
|
macd_sell = False
|
|
if slow_k_sell:
|
|
for idx in range(i, i-10, -1):
|
|
if data['macd'][idx - 1] > 0 and data['macds'][idx - 1] > 0 and data['macd'][idx] > 0 and data['macds'][idx] > 0:
|
|
if data['macd'][idx-1] > data['macds'][idx-1] and data['macd'][idx] < data['macds'][idx]:
|
|
macd_sell = True
|
|
break
|
|
|
|
# 3) RSI 지수가 50위로 올라갈 때
|
|
if macd_sell:
|
|
if data['rsi'][i-1] > 60 and data['rsi'][i] < 60:
|
|
sell, weight = data['close'][i], 1
|
|
|
|
return sell, weight
|
|
|
|
|
|
|
|
def analyze(self, result):
|
|
# 기본 캔들 정보
|
|
open = result["open"]
|
|
close = result["close"]
|
|
high = result["high"]
|
|
low = result["low"]
|
|
vol = result["vol"]
|
|
|
|
# 이동 평균
|
|
close_df = pd.DataFrame(close)
|
|
avg5_list = close_df.rolling(window=5).mean().fillna(close[0]).values.tolist()
|
|
avg5 = [item[0] for item in avg5_list]
|
|
avg20_list = close_df.rolling(window=20).mean().fillna(close[0]).values.tolist()
|
|
avg20 = [item[0] for item in avg20_list]
|
|
avg30_list = close_df.rolling(window=30).mean().fillna(close[0]).values.tolist()
|
|
avg30 = [item[0] for item in avg30_list]
|
|
avg60_list = close_df.rolling(window=60).mean().fillna(close[0]).values.tolist()
|
|
avg60 = [item[0] for item in avg60_list]
|
|
avg120_list = close_df.rolling(window=120).mean().fillna(close[0]).values.tolist()
|
|
avg120 = [item[0] for item in avg120_list]
|
|
avg200_list = close_df.rolling(window=200).mean().fillna(close[0]).values.tolist()
|
|
avg200 = [item[0] for item in avg200_list]
|
|
|
|
open_df = pd.DataFrame(close)
|
|
disparity_avg5_list = (open_df / close_df.rolling(window=5).mean()).values.tolist()
|
|
disparity_avg5 = [item[0] for item in disparity_avg5_list]
|
|
disparity_avg20_list = (open_df / close_df.rolling(window=20).mean()).values.tolist()
|
|
disparity_avg20 = [item[0] for item in disparity_avg20_list]
|
|
disparity_avg30_list = (open_df / close_df.rolling(window=30).mean()).values.tolist()
|
|
disparity_avg30 = [item[0] for item in disparity_avg30_list]
|
|
disparity_avg60_list = (open_df / close_df.rolling(window=60).mean()).values.tolist()
|
|
disparity_avg60 = [item[0] for item in disparity_avg60_list]
|
|
disparity_avg120_list = (open_df / close_df.rolling(window=120).mean()).values.tolist()
|
|
disparity_avg120 = [item[0] for item in disparity_avg120_list]
|
|
disparity_avg200_list = (open_df / close_df.rolling(window=200).mean()).values.tolist()
|
|
disparity_avg200 = [item[0] for item in disparity_avg200_list]
|
|
|
|
# 볼린져 밴드
|
|
df = pd.DataFrame(close)
|
|
max20 = df.rolling(window=20).mean()
|
|
stddev20 = df.rolling(window=20).std()
|
|
upper_df = max20 + (stddev20 * 2) # 상단 볼린저 밴드
|
|
lower_df = max20 - (stddev20 * 2) # 하단 볼린저 밴드
|
|
|
|
upper, lower = [], []
|
|
for i in range(len(upper_df)):
|
|
if i < 10:
|
|
upper.append(upper_df.values[0][0])
|
|
lower.append(lower_df.values[0][0])
|
|
else:
|
|
upper.append(upper_df.values[i][0])
|
|
lower.append(lower_df.values[i][0])
|
|
|
|
point_temp = result["time"]
|
|
STOCK = []
|
|
for i in range(len(open)):
|
|
STOCK.append({'volume': vol[i], 'close': close[i], 'open': open[i], 'high': high[i], 'low': low[i],
|
|
'avg5': avg5[i], 'avg20': avg20[i], 'avg30': avg30[i], 'avg60': avg60[i], 'avg120': avg120[i], 'avg200': avg200[i]})
|
|
|
|
# stochastic
|
|
stochastic_df = self.stochastic.apply(STOCK, n=30, m=5, t=5)
|
|
fast_k = stochastic_df['fast_k'].values.tolist()
|
|
slow_k = stochastic_df['slow_k'].values.tolist()
|
|
slow_d = stochastic_df['slow_d'].values.tolist()
|
|
|
|
# macd
|
|
#macd_df = self.macd.apply(STOCK, short=12, long=26, t=9)
|
|
macd_df = self.macd.apply(STOCK, short=5, long=20, t=5)
|
|
macd = macd_df['macd'].values.tolist()
|
|
macds = macd_df['macds'].values.tolist()
|
|
macdo = macd_df['macdo'].values.tolist()
|
|
|
|
# rsi
|
|
rsi_df = self.rsi.apply(STOCK, period=30, window=5)
|
|
rsi = rsi_df['rsi'].values.tolist()
|
|
rsis = rsi_df['rsis'].values.tolist()
|
|
|
|
# ichimokuCloud
|
|
ichimokuCloud_df = self.ichimokuCloud.apply(STOCK, c=9, b=26, l=52)
|
|
ichimokuCloud_df = ichimokuCloud_df[:len(ichimokuCloud_df) - 51]
|
|
changeLine = ichimokuCloud_df['changeLine'].values.tolist()
|
|
baseLine = ichimokuCloud_df['baseLine'].values.tolist()
|
|
laggingSpan = ichimokuCloud_df['laggingSpan'].values.tolist()
|
|
leadingSpan1 = ichimokuCloud_df['leadingSpan1'].values.tolist()
|
|
leadingSpan2 = ichimokuCloud_df['leadingSpan2'].values.tolist()
|
|
|
|
# 결과
|
|
temp = {
|
|
"date": point_temp,
|
|
"open": open, "high": high, "low": low, "close": close, "volume": vol,
|
|
"avg5": avg5, "avg20": avg20, "avg30": avg30, "avg60": avg60, "avg120": avg120, "avg200": avg200,
|
|
"disparity_avg5": disparity_avg5, "disparity_avg20": disparity_avg20, "disparity_avg30": disparity_avg30,
|
|
"disparity_avg60": disparity_avg60, "disparity_avg120": disparity_avg120, "disparity_avg200": disparity_avg200,
|
|
"upper": upper, "lower": lower,
|
|
"macd": macd, "macds": macds, "macdo": macdo,
|
|
"fast_k": fast_k, "slow_k": slow_k, "slow_d": slow_d,
|
|
"rsi": rsi, "rsis": rsis,
|
|
"changeLine": changeLine, "baseLine": baseLine, "laggingSpan": laggingSpan, "leadingSpan1": leadingSpan1,
|
|
"leadingSpan2": leadingSpan2,
|
|
}
|
|
|
|
data = pd.DataFrame(temp)
|
|
df_final_time = pd.DatetimeIndex(point_temp)
|
|
data.index = df_final_time
|
|
|
|
data = data.fillna(-1)
|
|
return data
|
|
|
|
def checkTransaction(self, stock_code, data, data_5=None, data_30=None, isRealTime=True):
|
|
# 어제 오늘 데이터로 분석
|
|
bsLine = {}
|
|
|
|
size = len(data["close"])
|
|
|
|
if isRealTime:
|
|
|
|
# isRealTime=True, 실시간 적용
|
|
last_index = size - 1
|
|
|
|
buy, buy_weight = self.getBuyPriceAndWeight(stock_code, last_index, data)
|
|
#sell, sell_weight = self.getSellPriceAndWeight(stock_code, last_index, data)
|
|
sell, sell_weight = -1, -1
|
|
if data.index[last_index].strftime('%H:%M:%S') > datetime.strptime(datetime.today().strftime("%Y-%m-%d 15:10:00"), "%Y-%m-%d %H:%M:%S").strftime('%H:%M:%S'):
|
|
buy, buy_weight = -1, -1
|
|
|
|
bsLine['buy'] = [buy]
|
|
bsLine['buy_weight'] = [buy_weight]
|
|
bsLine['sell'] = [sell]
|
|
bsLine['sell_weight'] = [sell_weight]
|
|
|
|
else:
|
|
# Type=False, 시뮬레이션 적용
|
|
bsLine['buy'] = [-1 for i in range(size)]
|
|
bsLine['buy_weight'] = [-1 for i in range(size)]
|
|
bsLine['sell'] = [-1 for i in range(size)]
|
|
bsLine['sell_weight'] = [-1 for i in range(size)]
|
|
|
|
for last_index in range(size):
|
|
|
|
buy, buy_weight = self.getBuyPriceAndWeight(stock_code, last_index, data)
|
|
sell, sell_weight = self.getSellPriceAndWeight(stock_code, last_index, data)
|
|
|
|
bsLine['buy'][last_index] = buy
|
|
bsLine['buy_weight'][last_index] = buy_weight
|
|
bsLine['sell'][last_index] = sell
|
|
bsLine['sell_weight'][last_index] = sell_weight
|
|
|
|
return bsLine
|
|
|
|
def checkTransactionML(self, data, stock_code, predY, isRealTime=True):
|
|
# 4일치 중에서 앞에 2일은 제거한다.
|
|
date = data['date'].dt.date.unique().tolist()
|
|
data = data[data['date'].dt.date != date[0]]
|
|
data = data[data['date'].dt.date != date[1]]
|
|
|
|
# 어제 오늘 데이터로 분석
|
|
bsLine = {}
|
|
size = len(data["close"])
|
|
if isRealTime:
|
|
# isRealTime=True, 실시간 적용
|
|
last_index = size - 1
|
|
|
|
# Type=False, 시뮬레이션 적용
|
|
bsLine['buy'] = [-1 for i in range(size)]
|
|
bsLine['buy_weight'] = [-1 for i in range(size)]
|
|
bsLine['sell'] = [-1 for i in range(size)]
|
|
bsLine['sell_weight'] = [-1 for i in range(size)]
|
|
|
|
sell, sell_weight, buy, buy_weight = -1, -1, -1, -1
|
|
if predY[last_index] == 1:
|
|
sell = int((data["open"][last_index] + data["close"][last_index]) / 2)
|
|
sell_weight = 1
|
|
elif predY[last_index] == 2:
|
|
buy = int((data["open"][last_index] + data["close"][last_index]) / 2)
|
|
buy_weight = 1
|
|
|
|
bsLine['buy'] = [buy]
|
|
bsLine['buy_weight'] = [buy_weight]
|
|
bsLine['sell'] = [sell]
|
|
bsLine['sell_weight'] = [sell_weight]
|
|
else:
|
|
# Type=False, 시뮬레이션 적용
|
|
bsLine['buy'] = [-1 for i in range(size)]
|
|
bsLine['buy_weight'] = [-1 for i in range(size)]
|
|
bsLine['sell'] = [-1 for i in range(size)]
|
|
bsLine['sell_weight'] = [-1 for i in range(size)]
|
|
|
|
for i in range(size):
|
|
if predY[i] == 1:
|
|
bsLine['sell'][i] = int((data["open"][i] + data["close"][i]) / 2)
|
|
bsLine['sell_weight'][i] = 1
|
|
elif predY[i] == 2:
|
|
bsLine['buy'][i] = int((data["open"][i] + data["close"][i]) / 2)
|
|
bsLine['buy_weight'][i] = 1
|
|
|
|
return bsLine, data
|
|
|
|
# middle line에 맞다은 적 없이, low line에 붙었거나 아래에 있었던 캔들의 높은 가격을 얻어옴
|
|
def getPrice_UnderLowWithoutMiddle(self, last_index, data):
|
|
if data['high'][last_index] < data['envelope_middle'][last_index]:
|
|
for i in range(last_index - 1, 0, -1):
|
|
if data['high'][i] > data['envelope_middle'][i]:
|
|
return -1, -1
|
|
if data['low'][i] < data['envelope_lower'][i]:
|
|
return i, max(data['open'][i], data['close'][i])
|
|
return -1, -1
|
|
|
|
def getBuyPriceAndWeight_Envelope(self, i, data):
|
|
buy, weight = -1, -1
|
|
|
|
"""
|
|
# middle line에 맞다은 적 없이, low line에 붙었거나 아래에 있었던 캔들의 높은 가격을 얻어옴
|
|
index, price = self.getPrice_UnderLowWithoutMiddle(i, data)
|
|
if price > -1:
|
|
# 해당 가격보다 높은 가격이면 매수한다
|
|
if price < data['close'][i]:
|
|
buy = data['close'][i]
|
|
weight = 10
|
|
"""
|
|
if i > 100:
|
|
if -0.004 < data['gradient1'][i] < 0.001:
|
|
# if data['high'][i] < data['envelope_middle'][i]:
|
|
if data['slow_k'][i] < 20:
|
|
buy = data['close'][i]
|
|
weight = 10
|
|
|
|
"""
|
|
if i > 100:
|
|
if min(data['gradient1'][i-5:i]) < -0.009 and -0.009 < data['gradient1'][i]:
|
|
if data['high'][i] < data['envelope_middle'][i]:
|
|
buy = data['close'][i]
|
|
weight = 10
|
|
"""
|
|
return buy, weight
|
|
|
|
def getSellPriceAndWeight_Envelope(self, data, i):
|
|
sell, weight, type = -1, -1, -1
|
|
|
|
if data.index[i].strftime("%Y.%m.%d") == "2022.12.01":
|
|
print(1)
|
|
|
|
# upper lined에서 처리
|
|
if data['close'][i - 1] < data['envelope_upper'][i - 1] and data['envelope_upper'][i] < data['close'][i]:
|
|
if data['slow_d'][i - 1] <= data['slow_k'][i - 1] and data['slow_k'][i] <= data['slow_d'][i]:
|
|
sell = data["close"][i]
|
|
weight = 1
|
|
type = 1
|
|
if data['envelope_upper'][i - 1] < data['close'][i - 1] and data['envelope_upper'][i] < data['close'][i]:
|
|
if data['slow_d'][i - 1] <= data['slow_k'][i - 1] and data['slow_k'][i] <= data['slow_d'][i]:
|
|
sell = data["close"][i]
|
|
weight = 1
|
|
type = 2
|
|
if data['envelope_upper'][i - 1] < data['close'][i - 1] and data['envelope_upper'][i] < data['close'][i]:
|
|
if data['slow_d'][i - 1] + 2 <= data['slow_k'][i - 1] and data['slow_d'][i] + 1 == data['slow_k'][i]:
|
|
sell = data["close"][i]
|
|
weight = 1
|
|
type = 3
|
|
|
|
if data['envelope_upper'][i] < data['high'][i] and data['open'][i] < data['close'][i]:
|
|
if data['close'][i] - data['open'][i] < data['high'][i] - data['close'][i]:
|
|
sell = data["close"][i]
|
|
weight = 1
|
|
type = 4
|
|
|
|
return sell, weight, type
|
|
|
|
# 팔아야 할 시점을 체크하기 위함
|
|
# 이전에 산 가격보다 지금 5원이상 떨어졌다면 매도 한다.
|
|
def checkBelow5WonFromPreviousBuyPrice(self, last_index, data, price):
|
|
for i in range(last_index - 1, 0, -1):
|
|
if data['sell'][i] != -1:
|
|
return False
|
|
if data['buy'][i] != -1:
|
|
if data['buy'][i] - price > 5:
|
|
return True
|
|
return
|
|
|
|
def checkWithEnvelope_252670(self, data, isRealTime=False):
|
|
|
|
bsLine = {}
|
|
size = len(data["close"])
|
|
|
|
bsLine['buy'] = [-1 for i in range(size)]
|
|
bsLine['buy_weight'] = [-1.0 for i in range(size)]
|
|
bsLine['sell'] = [-1 for i in range(size)]
|
|
bsLine['sell_weight'] = [-1.0 for i in range(size)]
|
|
|
|
for i in range(size):
|
|
if isRealTime:
|
|
if i < size - 1:
|
|
continue
|
|
|
|
"""
|
|
# 이전에 산 가격보다 지금 5원이상 떨어졌다면 매도 한다.
|
|
price = data['close'][i] if data['close'][i] >= data['open'][i] else data['open'][i]
|
|
if self.checkBelow5WonFromPreviousBuyPrice(i, data, price):
|
|
data['sell'][i] = price
|
|
bsLine['sell'][i] = price
|
|
bsLine['sell_weight'][i] = 50
|
|
return bsLine, data
|
|
"""
|
|
|
|
"""
|
|
# middle line에 맞다은 적 없이, low line에 붙었거나 아래에 있었던 캔들의 높은 가격을 얻어옴
|
|
buy, buy_weight = self.getBuyPriceAndWeight_Envelope(i, data)
|
|
data['buy'][i] = buy
|
|
bsLine['buy'][i] = buy
|
|
bsLine['buy_weight'][i] = buy_weight
|
|
return bsLine, data
|
|
"""
|
|
|
|
if 0 < data['gradients_avg60'][i] < 0.001:
|
|
if data['high'][i] < data['envelope_middle'][i]:
|
|
if -0.015 < data['gradients_avg5'][i] and -0.007 < data['gradients_avg20'][i]:
|
|
buy = data['low'][i]
|
|
data['buy'][i] = buy
|
|
bsLine['buy'][i] = buy
|
|
bsLine['buy_weight'][i] = 20.0
|
|
|
|
if i > 10:
|
|
if (
|
|
data['gradients_avg60'][i - 10] > 0 and data['gradients_avg60'][i - 9] > 0 and
|
|
data['gradients_avg60'][i - 8] > 0 and
|
|
data['gradients_avg60'][i - 7] > 0 and data['gradients_avg60'][i - 6] > 0 and
|
|
data['gradients_avg60'][i - 5] > 0 and
|
|
data['gradients_avg60'][i - 4] > 0 and data['gradients_avg60'][i - 3] > 0 and
|
|
data['gradients_avg60'][i - 2] > 0 and
|
|
data['gradients_avg60'][i - 1] > 0 and data['gradients_avg60'][i] < 0
|
|
):
|
|
if data['disparity'][i] < 3:
|
|
buy = data['low'][i]
|
|
data['buy'][i] = buy
|
|
bsLine['buy'][i] = buy
|
|
bsLine['buy_weight'][i] = 20.0
|
|
|
|
if data['disparity_avg60'][i] < 65:
|
|
buy = data['low'][i]
|
|
data['buy'][i] = buy
|
|
bsLine['buy'][i] = buy
|
|
bsLine['buy_weight'][i] = 15.0
|
|
|
|
if data['slow_k'][i] < 3:
|
|
buy = data['low'][i]
|
|
data['buy'][i] = buy
|
|
bsLine['buy'][i] = buy
|
|
bsLine['buy_weight'][i] = 10.0
|
|
|
|
if not (data['avg120'][i - 1] < data['avg60'][i - 1] < data['avg20'][i - 1] < data['avg5'][i - 1]) and (data['avg120'][i] < data['avg60'][i] < data['avg20'][i] < data['avg5'][i]):
|
|
buy = data['low'][i]
|
|
data['buy'][i] = buy
|
|
bsLine['buy'][i] = buy
|
|
bsLine['buy_weight'][i] = 20.0
|
|
|
|
return bsLine, data
|
|
|
|
def checkWithEnvelope_122630(self, data, isRealTime=False):
|
|
|
|
bsLine = {}
|
|
size = len(data["close"])
|
|
|
|
bsLine['buy'] = [-1 for i in range(size)]
|
|
bsLine['buy_weight'] = [-1.0 for i in range(size)]
|
|
bsLine['sell'] = [-1 for i in range(size)]
|
|
bsLine['sell_weight'] = [-1.0 for i in range(size)]
|
|
|
|
for i in range(size):
|
|
if isRealTime:
|
|
if i < size - 1:
|
|
continue
|
|
|
|
if i > 10:
|
|
if data['disparity_avg60'][i] < 60:
|
|
buy = data['low'][i]
|
|
data['buy'][i] = buy
|
|
bsLine['buy'][i] = buy
|
|
bsLine['buy_weight'][i] = 20.0
|
|
|
|
if data['macd'][i] < -1000:
|
|
buy = data['low'][i]
|
|
data['buy'][i] = buy
|
|
bsLine['buy'][i] = buy
|
|
bsLine['buy_weight'][i] = 20.0
|
|
|
|
if data['slow_k'][i] < 7:
|
|
if data['slow_d'][i] < data['slow_k'][i]:
|
|
buy = data['low'][i]
|
|
data['buy'][i] = buy
|
|
bsLine['buy'][i] = buy
|
|
bsLine['buy_weight'][i] = 10.0
|
|
|
|
if not (data['avg120'][i - 1] < data['avg60'][i - 1] < data['avg20'][i - 1] < data['avg5'][i - 1]) and (data['avg120'][i] < data['avg60'][i] < data['avg20'][i] < data['avg5'][i]):
|
|
buy = data['low'][i]
|
|
data['buy'][i] = buy
|
|
bsLine['buy'][i] = buy
|
|
bsLine['buy_weight'][i] = 25.0
|
|
|
|
return bsLine, data
|
|
|
|
def notBuy(self, data, i):
|
|
if i > 5:
|
|
check = True
|
|
for l in range(i - 4, i + 1):
|
|
if (
|
|
data['gradients_avg60'][l - 1] > data['gradients_avg60'][l] or
|
|
data['gradients_avg20'][l - 1] > data['gradients_avg20'][l] or
|
|
data['gradients_low'][l - 1] > data['gradients_low'][l]
|
|
):
|
|
check = False
|
|
break
|
|
if not check:
|
|
return False
|
|
return True
|
|
|
|
def checkWithEnvelope(self, data, analyzed_day=120, isRealTime=False):
|
|
|
|
bsLine = {}
|
|
size = len(data["close"])
|
|
|
|
bsLine['buy'] = [-1 for i in range(size)]
|
|
bsLine['buy_weight'] = [-1.0 for i in range(size)]
|
|
bsLine['sell'] = [-1 for i in range(size)]
|
|
bsLine['sell_weight'] = [-1.0 for i in range(size)]
|
|
|
|
gap_interval = analyzed_day
|
|
gap_state = False
|
|
for i in range(size):
|
|
if isRealTime:
|
|
if i < size - 1:
|
|
continue
|
|
|
|
if i > 10:
|
|
# 만약 전일 저가와 오늘 종의 차이가 1만원이 넘으면 향후 60일은 분석하지 않는다.
|
|
if data['high'][i] < int(data['low'][i - 1] * 0.7):
|
|
gap_state = True
|
|
gap_interval -= 1
|
|
continue
|
|
if gap_state:
|
|
if gap_interval <= 0:
|
|
gap_state = False
|
|
gap_interval = 60
|
|
else:
|
|
gap_interval -= 1
|
|
continue
|
|
|
|
if data['disparity'][i] < 2:
|
|
check = True
|
|
for l in range(i - 3, i):
|
|
if (
|
|
data['gradients_avg60'][l - 1] > data['gradients_avg60'][l] or
|
|
data['gradients_avg20'][l - 1] > data['gradients_avg20'][l] or
|
|
data['gradients_low'][l - 1] > data['gradients_low'][l] or
|
|
data['disparity_avg5'][l - 1] > data['disparity_avg5'][l] or
|
|
data['disparity'][l - 1] < data['disparity'][l]
|
|
):
|
|
check = False
|
|
break
|
|
if check and 99 < sum(data['disparity_avg5'][i - 4:i + 1]) / 5 < 100 and 99 < sum(data['disparity_avg60'][i - 4:i + 1]) / 5 < 100:
|
|
if data['slow_k'][i] < 30:
|
|
buy = data['low'][i]
|
|
data['buy'][i] = buy
|
|
bsLine['buy'][i] = buy
|
|
bsLine['buy_weight'][i] = 3.0
|
|
|
|
check = True
|
|
for l in range(i - 2, i):
|
|
if (data['gradients_avg60'][l - 1] > data['gradients_avg60'][l] or data['gradients_low'][l - 1] > data['gradients_low'][l]):
|
|
check = False
|
|
break
|
|
if (
|
|
check and
|
|
-0.0011 < data['gradients_low'][i] < 0 and -0.007 < data['gradients_avg5'][i] < 0.001 and
|
|
-0.0012 < data['gradients_avg60'][i] < 0 and
|
|
98.90 < data['disparity_avg5'][i] < 101
|
|
):
|
|
if data['slow_k'][i] < 30:
|
|
buy = data['low'][i]
|
|
data['buy'][i] = buy
|
|
bsLine['buy'][i] = buy
|
|
bsLine['buy_weight'][i] = 5.0
|
|
|
|
check = True
|
|
for l in range(i - 6, i):
|
|
if (
|
|
data['gradients_avg60'][l - 1] < data['gradients_avg60'][l] or
|
|
data['gradients_avg20'][l - 1] < data['gradients_avg20'][l] or
|
|
data['gradients_low'][l - 1] < data['gradients_low'][l] or
|
|
-0.039 < data['gradients_low'][l - 1] < -0.35 or
|
|
-0.05 < data['gradients_avg20'][l - 1] < -0.30 or
|
|
-0.40 < data['gradients_avg60'][l - 1] < -0.30
|
|
):
|
|
check = False
|
|
break
|
|
if check and 99 < min(data['disparity_avg5'][i - 6:i]) < max(data['disparity_avg5'][i - 6:i]) < 101:
|
|
if data['slow_k'][i] < 30:
|
|
buy = data['low'][i]
|
|
data['buy'][i] = buy
|
|
bsLine['buy'][i] = buy
|
|
bsLine['buy_weight'][i] = 5.0
|
|
"""
|
|
check = True
|
|
for l in range(i - 3, i):
|
|
if (
|
|
data['gradients_low'][l - 1] < data['gradients_low'][l] or
|
|
data['gradients_avg60'][l - 1] < data['gradients_avg60'][l] or
|
|
data['gradients_avg20'][l - 1] < data['gradients_avg20'][l] or
|
|
0.01 < data['gradients_low'][l - 1] < 0.21 or
|
|
-0.09 < data['gradients_avg20'][l - 1] < -0.002 or
|
|
0.01 < data['gradients_avg60'][l - 1] < 0.021
|
|
):
|
|
check = False
|
|
break
|
|
if check:
|
|
if data['slow_k'][i] < 30:
|
|
buy = data['low'][i]
|
|
data['buy'][i] = buy
|
|
bsLine['buy'][i] = buy
|
|
bsLine['buy_weight'][i] = 5.0
|
|
"""
|
|
|
|
|
|
if (data['disparity'][i] < 5 and 99.0 < data['disparity_avg60'][i] < 99.1 and
|
|
-0.009 < data['gradients_avg60'][i] < -0.008 and 0.015 < data['gradients_avg20'][i] < 0.016 and
|
|
-0.006 < data['gradients_avg5'][i] < -0.005 and -0.009 < data['gradients_low'][i] < -0.008):
|
|
check = True
|
|
for l in range(i - 5, i):
|
|
if (
|
|
data['gradients_avg60'][l - 1] > data['gradients_avg60'][l] or
|
|
data['gradients_low'][l - 1] > data['gradients_low'][l] or
|
|
data['disparity'][l - 1] < data['disparity'][l]
|
|
):
|
|
check = False
|
|
break
|
|
if check:
|
|
if data['slow_k'][i] < 10:
|
|
buy = data['low'][i]
|
|
data['buy'][i] = buy
|
|
bsLine['buy'][i] = buy
|
|
bsLine['buy_weight'][i] = 5.0
|
|
|
|
if data['macd'][i] < -4000:
|
|
if data['macd'][i - 1] < data['macd'][i]:
|
|
if not self.notBuy(data, i) and data['slow_k'][i] < 30:
|
|
if data['slow_k'][i] < 30:
|
|
buy = data['low'][i]
|
|
data['buy'][i] = buy
|
|
bsLine['buy'][i] = buy
|
|
bsLine['buy_weight'][i] = 5.0
|
|
|
|
# macd 이전에 없던 바닥인 경우 상승할 찰나 매수
|
|
if data['macds'][i - 1] < min(data['macds'][:i - 1]):
|
|
if data['macds'][i - 1] < data['macds'][i]:
|
|
if not self.notBuy(data, i) and data['slow_k'][i] < 30:
|
|
buy = data['low'][i]
|
|
data['buy'][i] = buy
|
|
bsLine['buy'][i] = buy
|
|
bsLine['buy_weight'][i] = 5.0
|
|
|
|
if (
|
|
98 < data['disparity_avg5'][i] < 100 and data['disparity_avg20'][i] < 93.5 and
|
|
data['disparity_avg60'][i] < 89 and
|
|
-0.014 < data['gradients_avg60'][i] < -0.013 and -0.03 < data['gradients_avg20'][
|
|
i] < -0.02 and -0.014 < data['gradients_low'][i] < -0.013 and
|
|
data['slow_k'][i] < 11
|
|
):
|
|
if not self.notBuy(data, i):
|
|
if data['slow_k'][i] < 30:
|
|
buy = data['low'][i]
|
|
data['buy'][i] = buy
|
|
bsLine['buy'][i] = buy
|
|
bsLine['buy_weight'][i] = 5.0
|
|
|
|
if data['slow_k'][i] < 20 and data['slow_k'][i - 1] < data['slow_d'][i - 1] and data['slow_d'][i] < data['slow_k'][i]:
|
|
if data['slow_k'][i] < 30:
|
|
buy = data['low'][i]
|
|
data['buy'][i] = buy
|
|
bsLine['buy'][i] = buy
|
|
bsLine['buy_weight'][i] = 7.0
|
|
|
|
if not (data['avg120'][i - 1] < data['avg60'][i - 1] < data['avg20'][i - 1] < data['avg5'][i - 1]) and (data['avg120'][i] < data['avg60'][i] < data['avg20'][i] < data['avg5'][i]):
|
|
if data['slow_k'][i] < 30:
|
|
buy = data['low'][i]
|
|
data['buy'][i] = buy
|
|
bsLine['buy'][i] = buy
|
|
bsLine['buy_weight'][i] = 10.0
|
|
|
|
|
|
if data['slow_k'][i] > 75:
|
|
if (data['slow_d'][i-1] < data['slow_k'][i-1] and data['slow_k'][i] < data['slow_d'][i]):
|
|
sell = data['close'][i]
|
|
weight = 100
|
|
data['sell'][i] = sell
|
|
bsLine['sell'][i] = sell
|
|
bsLine['sell_weight'][i] = weight
|
|
|
|
if data['slow_k'][i] > 85:
|
|
if data['slow_k'][i] < data['slow_d'][i]:
|
|
sell = data['close'][i]
|
|
weight = 100
|
|
data['sell'][i] = sell
|
|
bsLine['sell'][i] = sell
|
|
bsLine['sell_weight'][i] = weight
|
|
|
|
return bsLine, data
|
|
|
|
def checkTransactionWithEnvelope(self, data, stock_code, analyzed_day, isRealTime=False):
|
|
if isRealTime:
|
|
if stock_code == "252670":
|
|
bsLine, data = self.checkWithEnvelope_252670(data, isRealTime)
|
|
elif stock_code == "122630":
|
|
bsLine, data = self.checkWithEnvelope_122630(data, isRealTime)
|
|
else:
|
|
bsLine, data = self.checkWithEnvelope(data, analyzed_day, isRealTime)
|
|
else:
|
|
# 사야 할 시점과 팔아야 할 시점을 체크한다.
|
|
if stock_code == "252670":
|
|
bsLine, data = self.checkWithEnvelope_252670(data, isRealTime)
|
|
elif stock_code == "122630":
|
|
bsLine, data = self.checkWithEnvelope_122630(data, isRealTime)
|
|
else:
|
|
bsLine, data = self.checkWithEnvelope(data, analyzed_day, isRealTime)
|
|
|
|
return bsLine, data
|