294 lines
14 KiB
Python
294 lines
14 KiB
Python
import os
|
|
from dtw import dtw
|
|
import json
|
|
import sqlite3
|
|
import numpy as np
|
|
from datetime import datetime, timedelta
|
|
|
|
class BuySellChecker():
|
|
|
|
PATTERNS = None
|
|
RESOURCE_PATH = None
|
|
|
|
def __init__(self, RESOURCE_PATH, s):
|
|
self.RESOURCE_PATH = RESOURCE_PATH
|
|
return
|
|
|
|
def nearDisparity(self, data, i):
|
|
if (0.998 < data['disparity_avg5'][i] < 1.002 and
|
|
0.998 < data['disparity_avg5'][i] < 1.002 and
|
|
0.998 < data['disparity_avg5'][i] < 1.002 and
|
|
0.998 < data['disparity_avg5'][i] < 1.002 and
|
|
0.998 < data['disparity_avg5'][i] < 1.002):
|
|
return True
|
|
return False
|
|
|
|
def cosine_similarity(self, x, y):
|
|
return np.dot(x, y) / (np.sqrt(np.dot(x, x)) * np.sqrt(np.dot(y, y)))
|
|
|
|
"""
|
|
def findBuyPoint(self, data, data_signal, i):
|
|
# 코사인 유사도(cosine similarity)로 과거 주가의 유사 패턴을 찾아 미래 예측하기
|
|
# https://teddylee777.github.io/pandas/cos-sim-stock/
|
|
|
|
buy_target = data['close'].iloc[i-179:i+1]
|
|
window_size = len(buy_target)
|
|
if window_size == 180:
|
|
buy_target = (buy_target - buy_target.min()) / (buy_target.max() - buy_target.min())
|
|
for pattern in self.PATTERNS:
|
|
cos_similarity = self.cosine_similarity(pattern, buy_target)
|
|
if 0.995 < cos_similarity:
|
|
return True
|
|
|
|
return False
|
|
"""
|
|
|
|
def findBuyPoint(self, data, i):
|
|
# DTW (Dynamic Time Warping)
|
|
# 시계열 유사도: https://m.blog.naver.com/happyrachy/221693939341
|
|
if i < 24:
|
|
return False
|
|
|
|
for p in range(len(self.PATTERNS['min_max'])):
|
|
size = len(self.PATTERNS['stndardization'][p])
|
|
if i - size + 1 < 0:
|
|
continue
|
|
|
|
close = data['close'].iloc[i-size+1:i+1]
|
|
|
|
#min_max = np.array(self.PATTERNS['min_max'][p]).reshape(-1, 1)
|
|
stndardization = np.array(self.PATTERNS['stndardization'][p]).reshape(-1, 1)
|
|
|
|
#min_max_y = np.array((close - close.min()) / (close.max() - close.min())).reshape(-1, 1)
|
|
stndardization_y = np.array((close - close.mean()) / close.std()).reshape(-1, 1)
|
|
|
|
#manhattan_distance = lambda min_max, min_max_y: np.abs(min_max - min_max_y)
|
|
#min_max_d, cost_matrix, acc_cost_matrix, path = dtw(min_max, min_max_y, dist=manhattan_distance)
|
|
|
|
manhattan_distance = lambda stndardization, stndardization_y: np.abs(stndardization - stndardization_y)
|
|
stndardization_d, cost_matrix, acc_cost_matrix, path = dtw(stndardization, stndardization_y, dist=manhattan_distance)
|
|
|
|
if stndardization_d < 2:
|
|
#print(i, data['ymd'].iloc[i], stndardization_d)
|
|
return True
|
|
return False
|
|
|
|
def getMacd(self, ticker_code, day, mins=1):
|
|
|
|
table = 'minutely_max_macd_' + str(mins)
|
|
|
|
conn = sqlite3.connect(os.path.join(self.RESOURCE_PATH, 'coins.db'))
|
|
cursor = conn.cursor()
|
|
|
|
day1 = (datetime.strptime(day, '%Y%m%d') - timedelta(1)).strftime('%Y%m%d')
|
|
cursor.execute('SELECT ymd, hms, macd, close FROM '+table+' WHERE (CODE=? or CODE=?) and (ymd=? or ymd=?) order by macd desc', (ticker_code, ticker_code.replace('KRW-', ''), day, day1, ))
|
|
db_result1 = cursor.fetchall()
|
|
|
|
cursor.close()
|
|
conn.close()
|
|
|
|
macd_limit = [(datetime.strptime(rows[0]+" "+rows[1], '%Y%m%d %H%M%S'), rows[2], rows[3]) for rows in db_result1]
|
|
macd_dup = list(set(macd_limit))
|
|
return macd_dup
|
|
|
|
|
|
def is_Support(self, df, i, observation_time=300):
|
|
# c1 = df.Low[i] < df.Low[i - 1] < df.Low[i - 2] < df.Low[i - 3]
|
|
# c2 = df.Low[i] < df.Low[i + 1] < df.Low[i + 2] < df.Low[i + 3]
|
|
# return c1 & c2
|
|
|
|
#if df['low'][i] == np.min(df['low'][i - self.observation_time:i + self.observation_time + 1]):
|
|
if df['low'][i] == np.min(df['low'][i - observation_time:i+1]):
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def is_Resistance(self, df, i, observation_time = 300):
|
|
# c1 = df.High[i] > df.High[i - 1] > df.High[i - 2] > df.High[i - 3]
|
|
# c2 = df.High[i] > df.High[i + 1] > df.High[i + 2] > df.High[i + 3]
|
|
# return c1 & c2
|
|
#if df['high'][i] == np.max(df['high'][i - self.observation_time:i + self.observation_time + 1]):
|
|
if df['high'][i] == np.max(df['high'][i - observation_time:i+1]):
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def getBuyPriceAndWeight1(self, ticker, MAX_BUY_PRICE, i, data, data_signal, BUY_LIST, isRealTime=True):
|
|
buy_ymd, buy_price, buy_count, buy_cut, buy_type = None, -1, -1, -1, ''
|
|
|
|
df_tmp = data_signal['ymd'] <= data['ymd'][i]
|
|
df_signal = data_signal.loc[df_tmp]
|
|
si = len(df_signal) - 1
|
|
|
|
"""
|
|
duration = 5
|
|
if duration < i:
|
|
if sum(data['avg20'][i - duration:i])/len(data['avg20'][i - duration:i]) < data['avg20'][i]:
|
|
min_value1 = min(data['close'][i - 1], data['close'][i - 1])
|
|
min_value2 = min(data['close'][i - 2], data['close'][i - 2])
|
|
min_value3 = min(data['close'][i - 3], data['close'][i - 3])
|
|
min_sum = min_value1 + min_value2 + min_value3
|
|
if min_sum / 3 < data['close'][i] and data['close'][i] == data['high'][i]:
|
|
if data['avg60'][i] < data['avg20'][i] and data['avg5'][i-1] < data['avg5'][i]:
|
|
if data['middle'][i-1] < data['middle'][i]:
|
|
if 0 < len(BUY_LIST['buy_list']):
|
|
if BUY_LIST['buy_list'][-1]['buy_price'] < data['close'][i]:
|
|
buy_price = data['close'][i]
|
|
buy_type = 'avg20_close_up'
|
|
buy_ymd = data['ymd'][i]
|
|
buy_cut = -1
|
|
if data['slow_k'][si] < 30:
|
|
buy_count = MAX_BUY_PRICE / (1 * data['close'][i])
|
|
elif data['slow_k'][si] < 50:
|
|
buy_count = MAX_BUY_PRICE / (1.5 * data['close'][i])
|
|
else:
|
|
buy_count = MAX_BUY_PRICE / (2 * data['close'][i])
|
|
|
|
return buy_ymd, buy_price, buy_count, buy_cut, buy_type
|
|
else:
|
|
buy_price = data['close'][i]
|
|
buy_type = 'avg20_close_up'
|
|
buy_ymd = data['ymd'][i]
|
|
buy_cut = -1
|
|
if data['slow_k'][si] < 30:
|
|
buy_count = MAX_BUY_PRICE / (1 * data['close'][i])
|
|
elif data['slow_k'][si] < 50:
|
|
buy_count = MAX_BUY_PRICE / (1.5 * data['close'][i])
|
|
else:
|
|
buy_count = MAX_BUY_PRICE / (2 * data['close'][i])
|
|
|
|
return buy_ymd, buy_price, buy_count, buy_cut, buy_type
|
|
"""
|
|
|
|
duration = 5
|
|
if duration < i:
|
|
if np.average(data['trend_avg'][i - duration:i]) < data['trend_avg'][i]:
|
|
if self.is_Support(data, i-10, observation_time = 300):
|
|
if data['open'][i] < data['close'][i]:
|
|
if np.max(data['high'][i-2:i]) < data['close'][i]:
|
|
|
|
buy_price = data['close'][i]
|
|
buy_type = 'support_300'
|
|
buy_ymd = data['ymd'][i]
|
|
buy_cut = data['close'][i] * 0.995
|
|
BUY_LIST['buy_limit'] = 0
|
|
if data['slow_k'][si] < 30:
|
|
buy_count = MAX_BUY_PRICE*5 / (data['close'][i])
|
|
elif data['slow_k'][si] < 50:
|
|
buy_count = MAX_BUY_PRICE*4 / (data['close'][i])
|
|
else:
|
|
buy_count = MAX_BUY_PRICE*3 / (data['close'][i])
|
|
|
|
return buy_ymd, buy_price, buy_count, buy_cut, buy_type
|
|
|
|
if data['slow_k'][i] < 15:
|
|
if data['slow_k'][i-1] < data['slow_d'][i-1] and data['slow_d'][i] < data['slow_k'][i]:
|
|
buy_price = data['close'][i]
|
|
buy_type = 'slow_k'
|
|
buy_ymd = data['ymd'][i]
|
|
buy_cut = data['close'][i] * 0.995
|
|
BUY_LIST['buy_limit'] = 0
|
|
buy_count = MAX_BUY_PRICE * 2 / (data['close'][i])
|
|
return buy_ymd, buy_price, buy_count, buy_cut, buy_type
|
|
|
|
return buy_ymd, buy_price, buy_count, buy_cut, buy_type
|
|
|
|
def getSellPriceAndWeight1(self, ticker, i, data, data_signal, BUY_LIST=None):
|
|
sell_price, sell_count, sell_type = -1, -1, ''
|
|
|
|
df_tmp = data_signal['ymd'] <= data['ymd'][i]
|
|
df_signal = data_signal.loc[df_tmp]
|
|
si = len(df_signal) - 1
|
|
|
|
if 0 < len(BUY_LIST['buy_list']):
|
|
duration = 5
|
|
if duration < i:
|
|
if data['trend_avg'][i] < np.average(data['trend_avg'][i - duration:i]):
|
|
if self.is_Resistance(data, i - 10, observation_time=300):
|
|
sell_price = data['close'][i]
|
|
sell_count = sum([price['buy_count'] for price in BUY_LIST['buy_list']])
|
|
|
|
if 75 < np.max(data_signal['rsi'][si-5:si]):
|
|
if self.is_Resistance(data, i - 10, observation_time=300):
|
|
sell_price = data['close'][i]
|
|
sell_count = sum([price['buy_count'] for price in BUY_LIST['buy_list']])
|
|
|
|
|
|
if 70 < data['slow_k'][i]:
|
|
if data['slow_d'][i-1] < data['slow_k'][i-1] and data['slow_k'][i] <= data['slow_d'][i]:
|
|
sell_price = data['close'][i]
|
|
sell_count = sum([price['buy_count'] for price in BUY_LIST['buy_list'] if price['buy_type'] == 'slow_k'])
|
|
sell_type = 'slow_k'
|
|
|
|
return sell_price, sell_count, sell_type
|
|
|
|
def checkTransaction1(self, ticker, MAX_BUY_PRICE, data, data_signal, BUY_LIST=None, isRealTime=True):
|
|
|
|
# 어제 오늘 데이터로 분석
|
|
bsLine = {}
|
|
|
|
if data is not None and 'close' in data.columns:
|
|
size = len(data["close"])
|
|
if isRealTime:
|
|
|
|
# isRealTime=True, 실시간 적용
|
|
last_index = size - 1
|
|
|
|
sell_price, sell_count, sell_type = self.getSellPriceAndWeight1(ticker, last_index, data, data_signal, BUY_LIST)
|
|
bsLine['sell_price'] = [sell_price]
|
|
bsLine['sell_count'] = [sell_count]
|
|
bsLine['sell_type'] = [sell_type]
|
|
|
|
if 0 < sell_price:
|
|
BUY_LIST['buy_limit'] = 0
|
|
BUY_LIST['buy_list'].clear()
|
|
else:
|
|
buy_ymd, buy_price, buy_count, buy_cut, buy_type = self.getBuyPriceAndWeight1(ticker, MAX_BUY_PRICE, last_index, data, data_signal, BUY_LIST, isRealTime)
|
|
bsLine['buy_ymd'] = [buy_ymd]
|
|
bsLine['buy_price'] = [buy_price]
|
|
bsLine['buy_count'] = [buy_count]
|
|
bsLine['buy_cut'] = [buy_cut]
|
|
bsLine['buy_type'] = [buy_type]
|
|
|
|
if 0 < buy_price:
|
|
BUY_LIST['buy_list'].append({'buy_ymd': buy_ymd, 'buy_price': buy_price, 'buy_count': buy_count, 'buy_cut': buy_cut, 'buy_type': buy_type})
|
|
else:
|
|
# Type=False, 시뮬레이션 적용
|
|
bsLine['buy_ymd'] = [-1 for i in range(size)]
|
|
bsLine['buy_price'] = [-1 for i in range(size)]
|
|
bsLine['buy_count'] = [-1 for i in range(size)]
|
|
bsLine['buy_cut'] = [-1 for i in range(size)]
|
|
bsLine['buy_type'] = ['' for i in range(size)]
|
|
bsLine['sell_price'] = [-1 for i in range(size)]
|
|
bsLine['sell_count'] = [-1 for i in range(size)]
|
|
bsLine['sell_type'] = ['' for i in range(size)]
|
|
|
|
for last_index in range(size):
|
|
|
|
sell_price, sell_count, sell_type = self.getSellPriceAndWeight1(ticker, last_index, data, data_signal, BUY_LIST)
|
|
bsLine['sell_price'][last_index] = sell_price
|
|
bsLine['sell_count'][last_index] = sell_count
|
|
bsLine['sell_type'] = [sell_type]
|
|
|
|
if 0 < sell_price:
|
|
BUY_LIST['buy_limit'] = 0
|
|
BUY_LIST['buy_list'].clear()
|
|
else:
|
|
buy_ymd, buy_price, buy_count, buy_cut, buy_type = self.getBuyPriceAndWeight1(ticker, MAX_BUY_PRICE, last_index, data, data_signal, BUY_LIST, isRealTime)
|
|
bsLine['buy_price'][last_index] = buy_price
|
|
bsLine['buy_count'][last_index] = buy_count
|
|
bsLine['buy_cut'][last_index] = buy_cut
|
|
bsLine['buy_type'][last_index] = buy_type
|
|
|
|
if 0 < buy_price:
|
|
BUY_LIST['buy_list'].append({'buy_ymd': buy_ymd, 'buy_price': buy_price, 'buy_count': buy_count, 'buy_cut': buy_cut, 'buy_type': buy_type})
|
|
|
|
else:
|
|
bsLine['buy_price'] = [-1]
|
|
bsLine['buy_count'] = [-1]
|
|
bsLine['buy_cut'] = [-1]
|
|
bsLine['buy_type'] = ['']
|
|
bsLine['sell_price'] = [-1]
|
|
bsLine['sell_count'] = [-1]
|
|
|
|
return bsLine |