init
This commit is contained in:
@@ -1,778 +0,0 @@
|
|||||||
import os
|
|
||||||
import time
|
|
||||||
import requests
|
|
||||||
import json
|
|
||||||
import ccxt
|
|
||||||
import pybithumb
|
|
||||||
import pandas as pd
|
|
||||||
from math import nan
|
|
||||||
import plotly.io as po
|
|
||||||
from plotly import subplots
|
|
||||||
import plotly.graph_objects as go
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
from sklearn.linear_model import LinearRegression
|
|
||||||
from sklearn.preprocessing import StandardScaler, MinMaxScaler
|
|
||||||
|
|
||||||
from stock.analysis.AnalyzerSqlite import AnalyzerSqlite
|
|
||||||
from hts.BuySellChecker import BuySellChecker
|
|
||||||
from hts.HTS import HTS
|
|
||||||
from stock.util.SlackBot import SlackBot
|
|
||||||
|
|
||||||
|
|
||||||
class Bithumb_minute(HTS):
|
|
||||||
RESOURCE_PATH = None
|
|
||||||
buySellChecker = None
|
|
||||||
analyzerSqlite = None
|
|
||||||
bithumb = None
|
|
||||||
binance = None
|
|
||||||
TODAY = None
|
|
||||||
slackBot = None
|
|
||||||
stock_code = None
|
|
||||||
|
|
||||||
def __init__(self, RESOURCE_PATH, today):
|
|
||||||
super().__init__(RESOURCE_PATH)
|
|
||||||
self.slackBot = SlackBot()
|
|
||||||
self.stock_code = {"XRP": "리플"}
|
|
||||||
|
|
||||||
self.RESOURCE_PATH = RESOURCE_PATH
|
|
||||||
|
|
||||||
con_key = "946dd0b0e6f8ad411144cd33f09518d3" # 본인의 Connect Key를 입력한다.
|
|
||||||
sec_key = "56b2a3cdd9fe3a82aa3f38c97c161125" # 본인의 Secret Key를 입력한다.
|
|
||||||
|
|
||||||
self.buySellChecker = BuySellChecker()
|
|
||||||
self.analyzerSqlite = AnalyzerSqlite()
|
|
||||||
|
|
||||||
# bithumb api에 연결한 클라스 객체를 선언한다.
|
|
||||||
self.bithumb = pybithumb.Bithumb(con_key, sec_key)
|
|
||||||
self.binance = ccxt.binance()
|
|
||||||
self.TODAY = today
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
def bull_market(self, df, ticker):
|
|
||||||
m5 = df['close'].rolling(5).mean()
|
|
||||||
last_m5 = m5[-2]
|
|
||||||
|
|
||||||
price = pybithumb.get_current_price(ticker)
|
|
||||||
|
|
||||||
if price > last_m5:
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
def append(self, df, stock):
|
|
||||||
for i in range(len(df)):
|
|
||||||
stock['PRICE'].append(
|
|
||||||
{
|
|
||||||
"ymd": df.index[i],
|
|
||||||
"close": df['close'][i],
|
|
||||||
"diff": 0,
|
|
||||||
"open": df['open'][i],
|
|
||||||
"high": df['high'][i],
|
|
||||||
"low": df['low'][i],
|
|
||||||
"volume": df['volume'][i],
|
|
||||||
"avg3": -1,
|
|
||||||
"avg4": -1,
|
|
||||||
"avg5": -1,
|
|
||||||
"avg6": -1,
|
|
||||||
"avg10": -1,
|
|
||||||
"avg12": -1,
|
|
||||||
"avg20": -1,
|
|
||||||
"avg36": -1,
|
|
||||||
"avg40": -1,
|
|
||||||
"avg48": -1,
|
|
||||||
"avg60": -1,
|
|
||||||
"avg120": -1,
|
|
||||||
"avg200": -1,
|
|
||||||
"avg240": -1,
|
|
||||||
"avg300": -1,
|
|
||||||
"disparity_avg5": -1,
|
|
||||||
"disparity_avg10": -1,
|
|
||||||
"disparity_avg20": -1,
|
|
||||||
"disparity_avg60": -1,
|
|
||||||
"disparity_avg120": -1,
|
|
||||||
"bolingerband_upper": -1,
|
|
||||||
"bolingerband_lower": -1,
|
|
||||||
"bolingerband_middle": -1,
|
|
||||||
"envelope_upper": -1,
|
|
||||||
"envelope_lower": -1,
|
|
||||||
"envelope_middle": -1,
|
|
||||||
"ichimokucloud_changeLine": -1,
|
|
||||||
"ichimokucloud_baseLine": -1,
|
|
||||||
"ichimokucloud_leadingSpan1": -1,
|
|
||||||
"ichimokucloud_leadingSpan2": -1,
|
|
||||||
"stochastic_fast_k": -1,
|
|
||||||
"stochastic_slow_k": -1,
|
|
||||||
"stochastic_slow_d": -1,
|
|
||||||
"rsi": -1,
|
|
||||||
"rsis": -1,
|
|
||||||
"macd": -1,
|
|
||||||
"macds": -1,
|
|
||||||
"macdo": -1,
|
|
||||||
})
|
|
||||||
return
|
|
||||||
|
|
||||||
def analyze(self, stock, days=120):
|
|
||||||
stock["PRICE"] = sorted(stock["PRICE"], key=lambda x: x['ymd'])
|
|
||||||
self.analyzerSqlite.get_moving_average(stock["PRICE"])
|
|
||||||
|
|
||||||
# 이동 평균을 이용한 이격도 계산
|
|
||||||
self.analyzerSqlite.get_disparity(stock["PRICE"])
|
|
||||||
|
|
||||||
self.analyzerSqlite.ichimokuCloud.analyze(stock)
|
|
||||||
self.analyzerSqlite.stochastic.analyze(stock)
|
|
||||||
self.analyzerSqlite.bolingerBand.analyze(stock)
|
|
||||||
self.analyzerSqlite.envelope.analyze(stock)
|
|
||||||
self.analyzerSqlite.rsi.analyze(stock)
|
|
||||||
self.analyzerSqlite.macd.analyze(stock)
|
|
||||||
|
|
||||||
result = {
|
|
||||||
"ymd": [],
|
|
||||||
"open": [],
|
|
||||||
"close": [],
|
|
||||||
"high": [],
|
|
||||||
"low": [],
|
|
||||||
"avg3": [],
|
|
||||||
"avg4": [],
|
|
||||||
"avg5": [],
|
|
||||||
"avg6": [],
|
|
||||||
"avg10": [],
|
|
||||||
"avg12": [],
|
|
||||||
"avg20": [],
|
|
||||||
"avg36": [],
|
|
||||||
"avg40": [],
|
|
||||||
"avg48": [],
|
|
||||||
"avg60": [],
|
|
||||||
"avg120": [],
|
|
||||||
"avg200": [],
|
|
||||||
"avg240": [],
|
|
||||||
"avg300": [],
|
|
||||||
"disparity_avg5": [],
|
|
||||||
"disparity_avg20": [],
|
|
||||||
"disparity_avg60": [],
|
|
||||||
"disparity_avg120": [],
|
|
||||||
"disparity": [],
|
|
||||||
"disparity_type": [],
|
|
||||||
"envelope_upper": [],
|
|
||||||
"envelope_lower": [],
|
|
||||||
"envelope_middle": [],
|
|
||||||
"rsi": [],
|
|
||||||
"rsis": [],
|
|
||||||
"macd": [],
|
|
||||||
"macds": [],
|
|
||||||
"slow_k": [],
|
|
||||||
"slow_d": [],
|
|
||||||
"buy": [],
|
|
||||||
"sell": [],
|
|
||||||
}
|
|
||||||
for item in stock['PRICE']:
|
|
||||||
result["ymd"].append(item['ymd'])
|
|
||||||
result["open"].append(item['open'])
|
|
||||||
result["close"].append(item['close'])
|
|
||||||
result["high"].append(item['high'])
|
|
||||||
result["low"].append(item['low'])
|
|
||||||
result["avg3"].append(item['avg3'])
|
|
||||||
result["avg4"].append(item['avg4'])
|
|
||||||
result["avg5"].append(item['avg5'])
|
|
||||||
result["avg6"].append(item['avg6'])
|
|
||||||
result["avg10"].append(item['avg10'])
|
|
||||||
result["avg12"].append(item['avg12'])
|
|
||||||
result["avg20"].append(item['avg20'])
|
|
||||||
result["avg36"].append(item['avg36'])
|
|
||||||
result["avg40"].append(item['avg40'])
|
|
||||||
result["avg48"].append(item['avg48'])
|
|
||||||
result["avg60"].append(item['avg60'])
|
|
||||||
result["avg120"].append(item['avg120'])
|
|
||||||
result["avg200"].append(item['avg200'])
|
|
||||||
result["avg240"].append(item['avg240'])
|
|
||||||
result["avg300"].append(item['avg300'])
|
|
||||||
result["disparity_avg5"].append(item['disparity_avg5'])
|
|
||||||
result["disparity_avg20"].append(item['disparity_avg20'])
|
|
||||||
result["disparity_avg60"].append(item['disparity_avg60'])
|
|
||||||
result["disparity_avg120"].append(item['disparity_avg120'])
|
|
||||||
result['disparity'].append(
|
|
||||||
max(item['disparity_avg5'], item['disparity_avg20'], item['disparity_avg60']) - min(
|
|
||||||
item['disparity_avg5'], item['disparity_avg20'], item['disparity_avg60']))
|
|
||||||
if item['disparity_avg60'] < item['disparity_avg20'] < item['disparity_avg5']:
|
|
||||||
result['disparity_type'].append(1)
|
|
||||||
elif item['disparity_avg5'] < item['disparity_avg20'] < item['disparity_avg60']:
|
|
||||||
result['disparity_type'].append(-1)
|
|
||||||
else:
|
|
||||||
result['disparity_type'].append(0)
|
|
||||||
result["envelope_upper"].append(item['envelope_upper'])
|
|
||||||
result["envelope_lower"].append(item['envelope_lower'])
|
|
||||||
result["envelope_middle"].append(item['envelope_middle'])
|
|
||||||
result["rsi"].append(item['rsi'])
|
|
||||||
result["rsis"].append(item['rsis'])
|
|
||||||
result["macd"].append(item['macd'])
|
|
||||||
result["macds"].append(item['macds'])
|
|
||||||
result["slow_k"].append(item['stochastic_slow_k'])
|
|
||||||
result["slow_d"].append(item['stochastic_slow_d'])
|
|
||||||
result["buy"].append(-1)
|
|
||||||
result["sell"].append(-1)
|
|
||||||
|
|
||||||
data = pd.DataFrame(result)
|
|
||||||
df_final_time = pd.DatetimeIndex(result['ymd'])
|
|
||||||
data.index = df_final_time
|
|
||||||
|
|
||||||
data = data.astype(
|
|
||||||
{
|
|
||||||
'open': 'float',
|
|
||||||
'high': 'float',
|
|
||||||
'low': 'float',
|
|
||||||
'close': 'float',
|
|
||||||
'avg3': 'float',
|
|
||||||
'avg4': 'float',
|
|
||||||
'avg5': 'float',
|
|
||||||
'avg6': 'float',
|
|
||||||
'avg10': 'float',
|
|
||||||
'avg12': 'float',
|
|
||||||
'avg20': 'float',
|
|
||||||
'avg36': 'float',
|
|
||||||
'avg40': 'float',
|
|
||||||
'avg48': 'float',
|
|
||||||
'avg60': 'float',
|
|
||||||
'avg120': 'float',
|
|
||||||
'avg200': 'float',
|
|
||||||
'avg240': 'float',
|
|
||||||
'avg300': 'float',
|
|
||||||
'disparity_avg5': 'float',
|
|
||||||
'disparity_avg20': 'float',
|
|
||||||
'disparity_avg60': 'float',
|
|
||||||
'disparity_avg120': 'float',
|
|
||||||
'buy': 'float',
|
|
||||||
'sell': 'float',
|
|
||||||
'slow_k': 'float',
|
|
||||||
'slow_d': 'float',
|
|
||||||
'macd': 'float',
|
|
||||||
'macds': 'float',
|
|
||||||
'envelope_upper': 'float',
|
|
||||||
'envelope_lower': 'float',
|
|
||||||
'envelope_middle': 'float',
|
|
||||||
'rsi': 'float',
|
|
||||||
'rsis': 'float'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
scaler = StandardScaler()
|
|
||||||
low_df = pd.DataFrame(data['low'])
|
|
||||||
low_df.index = [c for c in range(len(low_df))]
|
|
||||||
low_std = scaler.fit_transform(data['low'].values.reshape(-1, 1))
|
|
||||||
low_std = pd.DataFrame(low_std, columns=['low_std'])
|
|
||||||
|
|
||||||
min_df = pd.DataFrame({'open': data['open'].to_list(), 'close': data['close'].to_list()})
|
|
||||||
min_df['min_std'] = min_df.min(axis=1)
|
|
||||||
min_df.index = [c for c in range(len(min_df))]
|
|
||||||
min_std = scaler.fit_transform(min_df['min_std'].values.reshape(-1, 1))
|
|
||||||
min_std = pd.DataFrame(min_std, columns=['min_std'])
|
|
||||||
|
|
||||||
line_fitter = LinearRegression()
|
|
||||||
size = len(data["close"])
|
|
||||||
gradients_low = []
|
|
||||||
gradients_avg5 = []
|
|
||||||
gradients_avg20 = []
|
|
||||||
gradients_avg60 = []
|
|
||||||
|
|
||||||
for i in range(size):
|
|
||||||
coef_low = -999
|
|
||||||
coef_avg5 = -999
|
|
||||||
coef_avg20 = -999
|
|
||||||
coef_avg60 = -999
|
|
||||||
|
|
||||||
if i > 0:
|
|
||||||
l = days if i >= days else i
|
|
||||||
x = pd.DataFrame([c for c in range(i - l, i + 1)])
|
|
||||||
y = pd.DataFrame(low_std.values.tolist()[i - l:i + 1])
|
|
||||||
line_fitter.fit(x.values.reshape(-1, 1), y)
|
|
||||||
coef_low = line_fitter.coef_[0][0]
|
|
||||||
|
|
||||||
l = 5 if i >= 5 else i
|
|
||||||
x = pd.DataFrame([c for c in range(i - l, i + 1)])
|
|
||||||
y = pd.DataFrame(min_std.values.tolist()[i - l:i + 1])
|
|
||||||
line_fitter.fit(x.values.reshape(-1, 1), y)
|
|
||||||
coef_avg5 = line_fitter.coef_[0][0]
|
|
||||||
|
|
||||||
l = 20 if i >= 20 else i
|
|
||||||
x = pd.DataFrame([c for c in range(i - l, i + 1)])
|
|
||||||
y = pd.DataFrame(min_std.values.tolist()[i - l:i + 1])
|
|
||||||
line_fitter.fit(x.values.reshape(-1, 1), y)
|
|
||||||
coef_avg20 = line_fitter.coef_[0][0]
|
|
||||||
|
|
||||||
l = 60 if i >= 60 else i
|
|
||||||
x = pd.DataFrame([c for c in range(i - l, i + 1)])
|
|
||||||
y = pd.DataFrame(min_std.values.tolist()[i - l:i + 1])
|
|
||||||
line_fitter.fit(x.values.reshape(-1, 1), y)
|
|
||||||
coef_avg60 = line_fitter.coef_[0][0]
|
|
||||||
|
|
||||||
gradients_low.append(coef_low)
|
|
||||||
gradients_avg5.append(coef_avg5)
|
|
||||||
gradients_avg20.append(coef_avg20)
|
|
||||||
gradients_avg60.append(coef_avg60)
|
|
||||||
|
|
||||||
gradients_low_df = pd.DataFrame(gradients_low, columns=['gradients_low'])
|
|
||||||
gradients_avg5_df = pd.DataFrame(gradients_avg5, columns=['gradients_avg5'])
|
|
||||||
gradients_avg20_df = pd.DataFrame(gradients_avg20, columns=['gradients_avg20'])
|
|
||||||
gradients_avg60_df = pd.DataFrame(gradients_avg60, columns=['gradients_avg60'])
|
|
||||||
|
|
||||||
gradients_low_df.index = df_final_time
|
|
||||||
gradients_avg5_df.index = df_final_time
|
|
||||||
gradients_avg20_df.index = df_final_time
|
|
||||||
gradients_avg60_df.index = df_final_time
|
|
||||||
|
|
||||||
data = data.merge(gradients_low_df, left_index=True, right_index=True)
|
|
||||||
data = data.merge(gradients_avg5_df, left_index=True, right_index=True)
|
|
||||||
data = data.merge(gradients_avg20_df, left_index=True, right_index=True)
|
|
||||||
data = data.merge(gradients_avg60_df, left_index=True, right_index=True)
|
|
||||||
|
|
||||||
return data
|
|
||||||
|
|
||||||
def writeFile(self, dirName, ticker, data, bsLine, type=None):
|
|
||||||
if bsLine is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
# 어제 데이터는 지운다.
|
|
||||||
buy_line = bsLine['buy']
|
|
||||||
buy_weight_line = bsLine['buy_weight']
|
|
||||||
sell_line = bsLine['sell']
|
|
||||||
|
|
||||||
buy_size = []
|
|
||||||
buy_colors = []
|
|
||||||
for i in range(len(buy_line)):
|
|
||||||
if buy_line[i] < 0:
|
|
||||||
buy_colors.append("#ffffff")
|
|
||||||
buy_line[i] = nan
|
|
||||||
buy_size.append(0)
|
|
||||||
else:
|
|
||||||
buy_colors.append("#B2028C")
|
|
||||||
buy_size.append(10 + (0.1 * buy_weight_line[i]))
|
|
||||||
|
|
||||||
sell_colors = []
|
|
||||||
for i in range(len(sell_line)):
|
|
||||||
if sell_line[i] < 0:
|
|
||||||
sell_colors.append("#ffffff")
|
|
||||||
sell_line[i] = nan
|
|
||||||
else:
|
|
||||||
sell_colors.append("#00ced1")
|
|
||||||
|
|
||||||
# 그래프를 설정한다.
|
|
||||||
buy_check = go.Scatter(x=data['ymd'], y=buy_line, mode='markers', name="buy", marker=dict(size=buy_size, color=buy_colors, line_width=0))
|
|
||||||
sell_check = go.Scatter(x=data['ymd'], y=sell_line, mode='markers', name="sell", marker=dict(size=14, color=sell_colors, line_width=0))
|
|
||||||
avg5 = go.Scatter(x=data['ymd'], y=data["avg5"], name="avg5", line_color='#6C2507')
|
|
||||||
avg20 = go.Scatter(x=data['ymd'], y=data["avg20"], name="avg20", line_color='#f84c43')
|
|
||||||
avg60 = go.Scatter(x=data['ymd'], y=data["avg60"], name="avg60", line_color='#f89543')
|
|
||||||
candle_stick = go.Candlestick(x=data['ymd'], open=data['open'], high=data['high'], low=data['low'], close=data['close'], increasing_line_color='red', decreasing_line_color='blue', showlegend=False)
|
|
||||||
|
|
||||||
macd_line = go.Scatter(x=data['ymd'], y=data["macd"], line=dict(color='red', width=2), name='macd')
|
|
||||||
macd_s_line = go.Scatter(x=data['ymd'], y=data["macds"], line=dict(dash='dashdot', color='black', width=2), name='macds')
|
|
||||||
|
|
||||||
# fast_k_line = go.Scatter(x=hts['date'], y=hts["fast_k"], mode='lines', name='fast_k')
|
|
||||||
slow_k_line = go.Scatter(x=data['ymd'], y=data["slow_k"], line=dict(color='red', width=2), name='slow_k')
|
|
||||||
slow_d_line = go.Scatter(x=data['ymd'], y=data["slow_d"], line=dict(dash='dashdot', color='black', width=2), name='slow_d')
|
|
||||||
|
|
||||||
rsi_line = go.Scatter(x=data['ymd'], y=data["rsi"], line=dict(color='red', width=2), name='rsi')
|
|
||||||
rsis_line = go.Scatter(x=data['ymd'], y=data["rsis"], line=dict(dash='dashdot', color='black', width=2), name='rsis')
|
|
||||||
|
|
||||||
disparity_avg5 = go.Scatter(x=data['ymd'], y=data["disparity_avg5"], name="disparity_avg5", line_color='#8F8203')
|
|
||||||
disparity_avg20 = go.Scatter(x=data['ymd'], y=data["disparity_avg20"], name="disparity_avg20", line_color='#ff00ff')
|
|
||||||
disparity_avg60 = go.Scatter(x=data['ymd'], y=data["disparity_avg60"], name="disparity_avg60", line_color='#1469F4')
|
|
||||||
|
|
||||||
candle_data = [candle_stick, avg5, avg20, avg60, buy_check, sell_check]
|
|
||||||
disparity_data = [disparity_avg5, disparity_avg20, disparity_avg60]
|
|
||||||
macd_data = [macd_line, macd_s_line]
|
|
||||||
stochastic_data = [slow_k_line, slow_d_line]
|
|
||||||
rsi_data = [rsi_line, rsis_line]
|
|
||||||
|
|
||||||
# 그래프를 그린다.
|
|
||||||
"""
|
|
||||||
fig = go.Figure(data=candle_data)
|
|
||||||
fig.update_layout(title=stock_code + "_" + given_day)
|
|
||||||
fig.show()
|
|
||||||
"""
|
|
||||||
|
|
||||||
fig = subplots.make_subplots(
|
|
||||||
rows=5, cols=1,
|
|
||||||
subplot_titles=("MACD", "RSI", "스토캐스틱", '이격도', '캔들'),
|
|
||||||
# specs=[[{}], [{}], [{}], [{}], [{}], [{}]],
|
|
||||||
shared_xaxes=True, horizontal_spacing=0.03, vertical_spacing=0.01,
|
|
||||||
row_heights=[200, 200, 200, 200, 750]
|
|
||||||
)
|
|
||||||
for trace in macd_data:
|
|
||||||
fig.append_trace(trace, 1, 1)
|
|
||||||
for trace in rsi_data:
|
|
||||||
fig.append_trace(trace, 2, 1)
|
|
||||||
for trace in stochastic_data:
|
|
||||||
fig.append_trace(trace, 3, 1)
|
|
||||||
for trace in disparity_data:
|
|
||||||
fig.append_trace(trace, 4, 1)
|
|
||||||
for trace in candle_data:
|
|
||||||
fig.append_trace(trace, 5, 1)
|
|
||||||
|
|
||||||
df = pd.DataFrame(bsLine)
|
|
||||||
df = df.fillna(-1)
|
|
||||||
buy_count = len(df.loc[df["buy"] > 0])
|
|
||||||
sell_count = len(df.loc[df["sell"] > 0])
|
|
||||||
|
|
||||||
fig.update_layout(height=1700, title="_" + str(buy_count) + "," + str(sell_count))
|
|
||||||
fig['layout'].update()
|
|
||||||
|
|
||||||
if type is None:
|
|
||||||
fileName = "%s/%s_%s.html" % (dirName, ticker, self.TODAY)
|
|
||||||
po.write_html(fig, file=fileName, auto_open=False)
|
|
||||||
else:
|
|
||||||
fileName = "%s/%s_%s_%s.html" % (dirName, type, ticker, self.TODAY)
|
|
||||||
po.write_html(fig, file=fileName, auto_open=False)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
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, data1, data2=None, isRealTime=False):
|
|
||||||
|
|
||||||
bsLine = {}
|
|
||||||
size = len(data1["close"])
|
|
||||||
|
|
||||||
bsLine['buy'] = [-1.0 for i in range(size)]
|
|
||||||
bsLine['buy_weight'] = [-1.0 for i in range(size)]
|
|
||||||
bsLine['sell'] = [-1.0 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 data1['slow_k'][i] < 20:
|
|
||||||
if data1['slow_k'][i - 1] < data1['slow_d'][i - 1] and data1['slow_d'][i] < data1['slow_k'][i]:
|
|
||||||
buy = data1['low'][i]
|
|
||||||
data1['buy'][i] = buy
|
|
||||||
bsLine['buy'][i] = buy
|
|
||||||
bsLine['buy_weight'][i] = 0.3
|
|
||||||
|
|
||||||
if data2['slow_k'][i] < 30 and data1['slow_k'][i] < 30:
|
|
||||||
if data1['slow_k'][i-1] < data1['slow_d'][i-1] and data1['slow_d'][i] < data2['slow_k'][i]:
|
|
||||||
buy = data1['close'][i]
|
|
||||||
data1['buy'][i] = buy
|
|
||||||
bsLine['buy'][i] = buy
|
|
||||||
bsLine['buy_weight'][i] = 0.3
|
|
||||||
|
|
||||||
|
|
||||||
if data2['slow_k'][i] < 30:
|
|
||||||
if data1['slow_k'][i] < 30:
|
|
||||||
if data1['avg5'][i] < data1['close'][i]:
|
|
||||||
buy = data1['close'][i]
|
|
||||||
data1['buy'][i] = buy
|
|
||||||
bsLine['buy'][i] = buy
|
|
||||||
bsLine['buy_weight'][i] = 0.2
|
|
||||||
|
|
||||||
if data1['slow_k'][i-1] < data1['slow_d'][i-1] and data1['slow_d'][i] < data2['slow_k'][i]:
|
|
||||||
buy = data1['close'][i]
|
|
||||||
data1['buy'][i] = buy
|
|
||||||
bsLine['buy'][i] = buy
|
|
||||||
bsLine['buy_weight'][i] = 0.3
|
|
||||||
|
|
||||||
if data2['slow_k'][i] > 90:
|
|
||||||
if (data1['slow_d'][i-1] < data1['slow_k'][i-1] and data1['slow_k'][i] < data1['slow_d'][i]):
|
|
||||||
sell = data1['close'][i]
|
|
||||||
data1['sell'][i] = sell
|
|
||||||
bsLine['sell'][i] = sell
|
|
||||||
bsLine['sell_weight'][i] = 100
|
|
||||||
|
|
||||||
if data1['slow_k'][i] > 95 and data1['slow_k'][i] < data1['slow_d'][i]:
|
|
||||||
sell = data1['close'][i]
|
|
||||||
data1['sell'][i] = sell
|
|
||||||
bsLine['sell'][i] = sell
|
|
||||||
bsLine['sell_weight'][i] = 100
|
|
||||||
|
|
||||||
if data2['slow_k'][i] > 98 and data1['slow_k'][i] > 98:
|
|
||||||
sell = data1['close'][i]
|
|
||||||
data1['sell'][i] = sell
|
|
||||||
bsLine['sell'][i] = sell
|
|
||||||
bsLine['sell_weight'][i] = 100
|
|
||||||
|
|
||||||
return bsLine
|
|
||||||
|
|
||||||
def get_ohlcv(self, ticker, minute=5):
|
|
||||||
url = "https://api.upbit.com/v1/candles/minutes/"+str(minute)
|
|
||||||
querystring = {"market": "KRW-"+ticker, "count": "300"}
|
|
||||||
response = requests.request("GET", url, params=querystring)
|
|
||||||
json_response = json.loads(response.text)
|
|
||||||
|
|
||||||
btc_ohlcv = []
|
|
||||||
for json_data in json_response:
|
|
||||||
btc_ohlcv.append({'datetime': datetime.strptime(json_data['candle_date_time_kst'], '%Y-%m-%dT%H:%M:%S'), 'open': json_data['opening_price'], 'high': json_data['high_price'], 'low': json_data['low_price'], 'close': json_data['trade_price'], 'volume': json_data['candle_acc_trade_volume']})
|
|
||||||
btc_ohlcv = sorted(btc_ohlcv, key=lambda item: (item['datetime']))
|
|
||||||
|
|
||||||
df = pd.DataFrame(btc_ohlcv, columns=['datetime', 'open', 'high', 'low', 'close', 'volume'])
|
|
||||||
df['datetime'] = pd.to_datetime(df['datetime'], unit='ms')
|
|
||||||
df.set_index('datetime', inplace=True)
|
|
||||||
df.insert(1, "datetime", df.index)
|
|
||||||
return df
|
|
||||||
|
|
||||||
def cancel_order(self, log_df, log_filename, min=5):
|
|
||||||
|
|
||||||
now = datetime.now() - timedelta(minutes=min)
|
|
||||||
# min 분 이상 된 시간인 내용을 가지고 옴
|
|
||||||
df = log_df.loc[(log_df.index <= now) ]
|
|
||||||
# 취소가 되지 않은 것만 가지고 옴 (0: 취소 되지 않음, 1: 취소함)
|
|
||||||
df = df.loc[(log_df["canceled"] == 0)]
|
|
||||||
|
|
||||||
if df is not None:
|
|
||||||
for i in range(len(df)):
|
|
||||||
order = (df['order0'][i], df['order1'][i], df['order2'][i], df['order3'][i])
|
|
||||||
cancel = self.bithumb.cancel_order(order)
|
|
||||||
# slackbot에 메시지를 보냄
|
|
||||||
#self.slackBot.post_to_slack(ticker, self.stock_code[ticker], "CANCEL", -1, -1)
|
|
||||||
|
|
||||||
for i in range(len(df)):
|
|
||||||
log_df.loc[(log_df.index == df.index[i]), 'canceled'] = 1
|
|
||||||
|
|
||||||
log_df.to_csv(log_filename, index=False)
|
|
||||||
|
|
||||||
return log_df
|
|
||||||
|
|
||||||
def check_buy_history(self, log_df, min=10):
|
|
||||||
# min 분 이상 된 시간인 내용을 가지고 옴
|
|
||||||
now = datetime.now() - timedelta(minutes=min)
|
|
||||||
# 취소가 되지 않은 것만 가지고 옴 (0: 취소 되지 않음, 1: 취소함)
|
|
||||||
log_df = log_df.loc[(now < log_df.index)]
|
|
||||||
|
|
||||||
if len(log_df) == 0:
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def getStock(self, ticker, analyzed_day, minute=5, day=None):
|
|
||||||
stock = {"CODE": ticker, "NAME": ticker, "PRICE": []}
|
|
||||||
|
|
||||||
if day is None:
|
|
||||||
df = self.get_ohlcv(ticker, minute)
|
|
||||||
else:
|
|
||||||
df = pybithumb.get_ohlcv(ticker)
|
|
||||||
df["datetime"] = df.index
|
|
||||||
close = pybithumb.get_current_price(ticker)
|
|
||||||
if df is None or close is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
size = len(df)
|
|
||||||
df['close'][size - 1] = close
|
|
||||||
if close < df['low'][size - 1]:
|
|
||||||
df['low'][size - 1] = close
|
|
||||||
if df['high'][size - 1] < close:
|
|
||||||
df['high'][size - 1] = close
|
|
||||||
self.append(df, stock)
|
|
||||||
|
|
||||||
data = self.analyze(stock, analyzed_day)
|
|
||||||
# 분석일 데이터만 활용한다 (이전 데이터는 제거)
|
|
||||||
data.drop(data.index[:len(data) - analyzed_day], inplace=True)
|
|
||||||
|
|
||||||
return data
|
|
||||||
|
|
||||||
def getXRPCount(self, price):
|
|
||||||
MAX_BUY_PRICE = 1000
|
|
||||||
if 870 < price: MAX_BUY_PRICE = 1000
|
|
||||||
elif 840 <= price < 870: MAX_BUY_PRICE = 2000
|
|
||||||
elif 810 <= price < 840: MAX_BUY_PRICE = 3000
|
|
||||||
elif 780 <= price < 810: MAX_BUY_PRICE = 4000
|
|
||||||
elif 750 <= price < 780: MAX_BUY_PRICE = 5000
|
|
||||||
elif 720 <= price < 750: MAX_BUY_PRICE = 6000
|
|
||||||
elif 690 <= price < 720: MAX_BUY_PRICE = 7000
|
|
||||||
elif 660 <= price < 690: MAX_BUY_PRICE = 8000
|
|
||||||
elif 630 <= price < 660: MAX_BUY_PRICE = 9000
|
|
||||||
elif 600 <= price < 630: MAX_BUY_PRICE = 10000
|
|
||||||
elif 570 <= price < 600: MAX_BUY_PRICE = 20000
|
|
||||||
elif 540 <= price < 570: MAX_BUY_PRICE = 30000
|
|
||||||
elif 510 <= price < 540: MAX_BUY_PRICE = 40000
|
|
||||||
elif 450 <= price < 480: MAX_BUY_PRICE = 50000
|
|
||||||
elif 420 <= price < 450: MAX_BUY_PRICE = 60000
|
|
||||||
elif 390 <= price < 420: MAX_BUY_PRICE = 70000
|
|
||||||
elif 360 <= price < 390: MAX_BUY_PRICE = 80000
|
|
||||||
elif 330 <= price < 360: MAX_BUY_PRICE = 90000
|
|
||||||
elif 300 <= price < 330: MAX_BUY_PRICE = 100000
|
|
||||||
elif 270 <= price < 300: MAX_BUY_PRICE = 110000
|
|
||||||
elif 240 <= price < 270: MAX_BUY_PRICE = 120000
|
|
||||||
elif 210 <= price < 240: MAX_BUY_PRICE = 130000
|
|
||||||
elif 180 <= price < 210: MAX_BUY_PRICE = 140000
|
|
||||||
elif 150 <= price < 180: MAX_BUY_PRICE = 150000
|
|
||||||
elif 120 <= price < 150: MAX_BUY_PRICE = 160000
|
|
||||||
elif 90 <= price < 120: MAX_BUY_PRICE = 170000
|
|
||||||
elif 60 <= price < 90: MAX_BUY_PRICE = 180000
|
|
||||||
elif 30 <= price < 60: MAX_BUY_PRICE = 190000
|
|
||||||
elif price < 30: MAX_BUY_PRICE = 200000
|
|
||||||
else: MAX_BUY_PRICE = 1000
|
|
||||||
|
|
||||||
count = int(MAX_BUY_PRICE / price)
|
|
||||||
return count
|
|
||||||
|
|
||||||
def buyRealTime(self, ticker, analyzed_day=120, isRealTime=False):
|
|
||||||
|
|
||||||
"""
|
|
||||||
# binance
|
|
||||||
btc_ohlcv = self.binance.fetch_ohlcv(ticker + "/BKRW")
|
|
||||||
df = pd.DataFrame(btc_ohlcv, columns=['datetime', 'open', 'high', 'low', 'close', 'volume'])
|
|
||||||
df['datetime'] = pd.to_datetime(df['datetime'], unit='ms')
|
|
||||||
df.set_index('datetime', inplace=True)
|
|
||||||
"""
|
|
||||||
|
|
||||||
"""
|
|
||||||
# bithumb
|
|
||||||
df_ = pybithumb.get_ohlcv(ticker)
|
|
||||||
"""
|
|
||||||
|
|
||||||
stock1 = self.getStock(ticker, analyzed_day, minute=5)
|
|
||||||
stock2 = self.getStock(ticker, analyzed_day, minute=30)
|
|
||||||
|
|
||||||
# 매수 매도 체크
|
|
||||||
bsLine = self.checkWithEnvelope(stock1, stock2, isRealTime=isRealTime)
|
|
||||||
print(ticker, "/", datetime.now().strftime('%Y-%m-%d %H:%M:%S'), "/", stock1['close'][len(stock1['close'])-1], "/", "{:.2f}".format(stock2['slow_k'][len(stock1['slow_k'])-1]), "/", "{:.2f}".format(stock1['slow_k'][len(stock1['slow_k'])-1]), "/", "{:.2f}".format(stock2['macd'][len(stock2['macd']) - 1]), "/", "{:.2f}".format(stock1['macd'][len(stock1['macd']) - 1]))
|
|
||||||
|
|
||||||
# 그래프를 그린다.
|
|
||||||
if len(stock1.index) > 10:
|
|
||||||
# 매수 요청 n분 이상된 주문은 취소하기 위함
|
|
||||||
order_log_filename = os.path.join(RESOURCE_PATH, 'order', "bithumb"+"_"+self.TODAY + '.log')
|
|
||||||
if os.path.exists(order_log_filename):
|
|
||||||
order_log_df = pd.read_csv(order_log_filename)
|
|
||||||
order_log_df.columns = ["type", "datetime", "order0", "order1", "order2", "order3", "canceled", "slow_k_30", "slow_k_5", "price", "count"]
|
|
||||||
order_log_df["datetime"] = pd.to_datetime(order_log_df["datetime"], format='%Y-%m-%d %H:%M:%S')
|
|
||||||
else:
|
|
||||||
order_log_df = pd.DataFrame(columns=["type", "datetime", "order0", "order1", "order2", "order3", "canceled", "slow_k_30", "slow_k_5", "price", "count"])
|
|
||||||
order_log_df['datetime'] = pd.to_datetime(order_log_df['datetime'], unit='s')
|
|
||||||
order_log_df.set_index('datetime', inplace=True)
|
|
||||||
order_log_df.insert(1, "datetime", order_log_df.index)
|
|
||||||
|
|
||||||
# 10분이 지난 미체결은 취소한다.
|
|
||||||
order_log_df = self.cancel_order(order_log_df, order_log_filename, min=10)
|
|
||||||
# 한번 매수 후 n분 이후 매수하기 위함
|
|
||||||
check_buy_history = self.check_buy_history(order_log_df, min=60)
|
|
||||||
|
|
||||||
if isRealTime and not check_buy_history:
|
|
||||||
# 매수 조건
|
|
||||||
if max(bsLine['buy'][len(bsLine['buy']) - 2:]) > 100:
|
|
||||||
|
|
||||||
#stock = self.getStock(ticker, analyzed_day, day=30)
|
|
||||||
#if stock["slow_k"][len(stock['close'])-1] > 40:
|
|
||||||
# print (datetime.now().strftime('%Y-%m-%d %H:%M:%S'), ",", round(stock["slow_k"][len(stock['close'])-3],2), ",", round(stock["slow_k"][len(stock['close'])-2],2), ",", round(stock["slow_k"][len(stock['close'])-1], ))
|
|
||||||
# return
|
|
||||||
|
|
||||||
# [잔고 확인하기]
|
|
||||||
# - 비트코인의 총 잔고
|
|
||||||
# - 거래 중인 비트코인의 수량
|
|
||||||
# - 보유 중인 총원화
|
|
||||||
# - 주문에 사용된 원화
|
|
||||||
# (4.978e-05, 0.0, 3438133.120299, 0)
|
|
||||||
tmp = self.bithumb.get_balance(ticker)
|
|
||||||
balance = tmp[2]
|
|
||||||
count = self.getXRPCount(bsLine['buy'][len(bsLine['buy']) - 1])
|
|
||||||
|
|
||||||
# 매수를 요청한다.
|
|
||||||
order = self.bithumb.buy_limit_order(ticker, bsLine['buy'][len(bsLine['buy']) - 1], count)
|
|
||||||
# slackbot에 메시지를 보냄
|
|
||||||
self.slackBot.post_to_slack(ticker, self.stock_code[ticker], "BUY", bsLine['buy'][len(bsLine['buy']) - 1], count)
|
|
||||||
|
|
||||||
# order: ('bid', 'BTC', 'C0101000000322993432', 'KRW')
|
|
||||||
if len(stock1['close']) > 0:
|
|
||||||
print(ticker, "/", datetime.now().strftime('%Y-%m-%d %H:%M:%S'), "/", stock1['close'][len(stock1['close'])-1], "/", "{:.2f}".format(stock2['slow_k'][len(stock1['slow_k'])-1]), "/", "{:.2f}".format(stock1['slow_k'][len(stock1['slow_k'])-1]), "/", "{:.2f}".format(stock2['macd'][len(stock2['macd']) - 1]), "/", "{:.2f}".format(stock1['macd'][len(stock1['macd']) - 1]), "/", bsLine['buy'][len(bsLine['buy']) - 1], "/", count)
|
|
||||||
datetime_value = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
|
||||||
value = {"type": "BUY", "datetime": datetime_value, "order0": order[0], "order1": order[1], "order2": order[2], "order3": order[3], "canceled": 0, "slow_k_30": stock2['slow_k'][len(stock2['slow_k']) - 1], "slow_k_5": stock1['slow_k'][len(stock1['slow_k']) - 1], "price": bsLine['buy'][len(bsLine['buy']) - 1], "count": count}
|
|
||||||
value_df = pd.DataFrame(value, index=[datetime_value])
|
|
||||||
value_df["datetime"] = pd.to_datetime(value_df["datetime"], format='%Y-%m-%d %H:%M:%S')
|
|
||||||
indexes1 = order_log_df.index.tolist()
|
|
||||||
indexes1.append(datetime_value)
|
|
||||||
|
|
||||||
order_log_df = order_log_df.append(value_df, ignore_index = True)
|
|
||||||
order_log_df.index = indexes1
|
|
||||||
order_log_df['datetime'] = order_log_df.index
|
|
||||||
order_log_df.to_csv(order_log_filename, index=False)
|
|
||||||
|
|
||||||
# 파일에 매수 시점 그래프
|
|
||||||
#dirName = os.path.join(RESOURCE_PATH, 'analysis', 'bithumb')
|
|
||||||
#self.writeFile(dirName, ticker, stock1, bsLine, 'buy')
|
|
||||||
|
|
||||||
"""
|
|
||||||
if max(bsLine['sell'][len(bsLine['sell']) - 2:]) > 100:
|
|
||||||
# [잔고 확인하기]
|
|
||||||
# - 비트코인의 총 잔고
|
|
||||||
# - 거래 중인 비트코인의 수량
|
|
||||||
# - 보유 중인 총원화
|
|
||||||
# - 주문에 사용된 원화
|
|
||||||
# (4.978e-05, 0.0, 3438133.120299, 0)
|
|
||||||
tmp = self.bithumb.get_balance(ticker)
|
|
||||||
if tmp is None:
|
|
||||||
return
|
|
||||||
count = tmp[0] - tmp[1]
|
|
||||||
|
|
||||||
# 매도를 요청한다.
|
|
||||||
order = self.bithumb.sell_limit_order(ticker, bsLine['sell'][len(bsLine['sell'])-1], count)
|
|
||||||
# slackbot에 메시지를 보냄
|
|
||||||
self.slackBot.post_to_slack(ticker, self.stock_code[ticker], "SELL", bsLine['sell'][len(bsLine['sell']) - 1], count)
|
|
||||||
|
|
||||||
if len(order) > 2 and len(stock1['close']) > 0:
|
|
||||||
print(ticker, "/", datetime.now().strftime('%Y-%m-%d %H:%M:%S'), "/", stock1['close'][len(stock1['close'])-1], "/", "{:.2f}".format(stock2['slow_k'][len(stock1['slow_k'])-1]), "/", "{:.2f}".format(stock1['slow_k'][len(stock1['slow_k'])-1]), "/", "{:.2f}".format(stock2['macd'][len(stock2['macd']) - 1]), "/", "{:.2f}".format(stock1['macd'][len(stock1['macd']) - 1]), "/", bsLine['sell'][len(bsLine['sell']) - 1], "/", count)
|
|
||||||
value = {"type": "SELL","order0": order[0], "order1": order[1], "order2": order[2], "order3": order[3], "canceled": 0, "slow_k_30": stock2['slow_k'][len(stock2['slow_k']) - 1], "slow_k_5": stock1['slow_k'][len(stock1['slow_k']) - 1], "price": bsLine['sell'][len(bsLine['sell']) - 1], "count": count}
|
|
||||||
datetime_value = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
|
||||||
value_df = pd.DataFrame(value, index=[datetime_value])
|
|
||||||
|
|
||||||
indexes = order_log_df.index.tolist()
|
|
||||||
indexes.append(datetime_value)
|
|
||||||
|
|
||||||
order_log_df = order_log_df.append(value_df, ignore_index=True)
|
|
||||||
order_log_df.index = indexes
|
|
||||||
order_log_df['datetime'] = order_log_df.index
|
|
||||||
order_log_df.to_csv(order_log_filename, index=False)
|
|
||||||
|
|
||||||
dirName = os.path.join(RESOURCE_PATH, 'analysis', 'bithumb')
|
|
||||||
self.writeFile(dirName, ticker, stock1, bsLine, 'sell')
|
|
||||||
"""
|
|
||||||
#else:
|
|
||||||
# dirName = os.path.join(RESOURCE_PATH, 'analysis', 'bithumb')
|
|
||||||
# self.writeFile(dirName, ticker, stock1, bsLine)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
|
|
||||||
PROJECT_HOME = os.getcwd()
|
|
||||||
RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources")
|
|
||||||
|
|
||||||
if not os.path.exists(os.path.join(RESOURCE_PATH, 'analysis', 'bithumb')):
|
|
||||||
os.mkdir(os.path.join(RESOURCE_PATH, 'analysis', 'bithumb'))
|
|
||||||
dirName = os.path.join(RESOURCE_PATH, 'analysis', 'bithumb')
|
|
||||||
if not os.path.exists(dirName):
|
|
||||||
os.mkdir(dirName)
|
|
||||||
|
|
||||||
# bithumb_daily = Bithumb_daily(RESOURCE_PATH)
|
|
||||||
today = datetime.today().strftime('%Y%m%d')
|
|
||||||
bithumb = Bithumb_minute(RESOURCE_PATH, today)
|
|
||||||
|
|
||||||
tickers = ['XRP']
|
|
||||||
analyzed_day = 120
|
|
||||||
isRealTime = True
|
|
||||||
if isRealTime:
|
|
||||||
while True:
|
|
||||||
for ticker in tickers:
|
|
||||||
#data_daily = bithumb_daily.buyRealTime(ticker, analyzed_day)
|
|
||||||
#size = len(data_daily)
|
|
||||||
#if data_daily['slow_k'] < 30:
|
|
||||||
try:
|
|
||||||
time.sleep(30)
|
|
||||||
bithumb.buyRealTime(ticker, analyzed_day, isRealTime)
|
|
||||||
except:
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
for ticker in tickers:
|
|
||||||
bithumb.buyRealTime(ticker, analyzed_day, isRealTime)
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
import pybithumb
|
|
||||||
|
|
||||||
con_key = "946dd0b0e6f8ad411144cd33f09518d3" # 본인의 Connect Key를 입력한다.
|
|
||||||
sec_key = "56b2a3cdd9fe3a82aa3f38c97c161125" # 본인의 Secret Key를 입력한다.
|
|
||||||
|
|
||||||
# bithumb api에 연결한 클라스 객체를 선언한다.
|
|
||||||
bithumb = pybithumb.Bithumb(con_key, sec_key)
|
|
||||||
|
|
||||||
def bull_market(ticker):
|
|
||||||
df = pybithumb.get_ohlcv(ticker)
|
|
||||||
m5 = df['close'].rolling(5).mean()
|
|
||||||
last_m5 = m5[-2]
|
|
||||||
|
|
||||||
price = pybithumb.get_current_price(ticker)
|
|
||||||
|
|
||||||
if price > last_m5:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
# 상장된 코인 Tickers 확인하기
|
|
||||||
#print (bithumb.get_tickers())
|
|
||||||
|
|
||||||
tickers = ['XRP']
|
|
||||||
|
|
||||||
|
|
||||||
for ticker in tickers:
|
|
||||||
# 과거 시세 얻기
|
|
||||||
result = pybithumb.get_ohlcv(ticker)
|
|
||||||
print(result)
|
|
||||||
|
|
||||||
is_bull = bull_market(ticker)
|
|
||||||
if is_bull:
|
|
||||||
print(ticker, "상승장")
|
|
||||||
else:
|
|
||||||
print(ticker, "하락장")
|
|
||||||
|
|
||||||
# [잔고 확인하기]
|
|
||||||
# - 비트코인의 총 잔고
|
|
||||||
# - 거래 중인 비트코인의 수량
|
|
||||||
# - 보유 중인 총원화
|
|
||||||
# - 주문에 사용된 원화
|
|
||||||
# (4.978e-05, 0.0, 3438133.120299, 0)
|
|
||||||
print (bithumb.get_balance(ticker))
|
|
||||||
|
|
||||||
# [매수]
|
|
||||||
# buy_limit_order() 메서드의 파라미터로 구매하고자 하는 가상화폐의
|
|
||||||
# 티커, 지정가, 매수 수량을 순서대로 입력합니다
|
|
||||||
# order = ('bid', 'BTC', 'C0101000000322993432', 'KRW')
|
|
||||||
order = bithumb.buy_limit_order(ticker, 300, 1)
|
|
||||||
print(order)
|
|
||||||
|
|
||||||
# 미체결 주문 확인
|
|
||||||
# get_balance를 통해 지정가 주문이 들어간 금액만큼 매수에 사용된 원화의 값이 확인된다. 39098.5에 해당된다.
|
|
||||||
# (0.04588863, 0.0, 3438133.120299, 39098.5)
|
|
||||||
# - 총 보유 수량
|
|
||||||
# - 현재 매도 거래에 사용 중인 코인 수량
|
|
||||||
# - 현재 보유하고 있는 원화 보유량. 즉 현금 보유액
|
|
||||||
# - 현재 매수 거래에 사용 중인 원화 보유량
|
|
||||||
print (bithumb.get_balance(ticker))
|
|
||||||
|
|
||||||
# 주문 취소 하기
|
|
||||||
cancel = bithumb.cancel_order(order)
|
|
||||||
print(cancel) # True
|
|
||||||
|
|
||||||
# 호가창 Order Book 살펴보기
|
|
||||||
orderbook = pybithumb.get_orderbook('BTC')
|
|
||||||
print (orderbook)
|
|
||||||
# bids의 최상단 66883000.0원이 매수 최상단 금액 (매수자가 기꺼이 지불하려고 하는 최대 금액)
|
|
||||||
# asks의 최상단 66919000.0원이 매도 최하단 금액 (판매자가 판매하고자 하는 최소 금액)
|
|
||||||
"""
|
|
||||||
{'timestamp': '1616913007272',
|
|
||||||
'payment_currency': 'KRW',
|
|
||||||
'order_currency': 'BTC',
|
|
||||||
'bids': [{'price': 66883000.0, 'quantity': 0.0951},
|
|
||||||
{'price': 66881000.0, 'quantity': 0.0607},
|
|
||||||
{'price': 66880000.0, 'quantity': 0.503},
|
|
||||||
{'price': 66878000.0, 'quantity': 0.0415},
|
|
||||||
{'price': 66868000.0, 'quantity': 0.0293}],
|
|
||||||
'asks': [{'price': 66919000.0, 'quantity': 0.9946},
|
|
||||||
{'price': 66927000.0, 'quantity': 0.002},
|
|
||||||
{'price': 66936000.0, 'quantity': 0.0382},
|
|
||||||
{'price': 66937000.0, 'quantity': 0.1541},
|
|
||||||
{'price': 66939000.0, 'quantity': 0.188}]}
|
|
||||||
"""
|
|
||||||
|
|
||||||
@@ -1,680 +0,0 @@
|
|||||||
import csv
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
import pybithumb
|
|
||||||
import pandas as pd
|
|
||||||
from math import nan
|
|
||||||
import plotly.io as po
|
|
||||||
from plotly import subplots
|
|
||||||
import plotly.graph_objects as go
|
|
||||||
from datetime import datetime
|
|
||||||
from sklearn.linear_model import LinearRegression
|
|
||||||
from sklearn.preprocessing import StandardScaler, MinMaxScaler
|
|
||||||
|
|
||||||
from stock.analysis.AnalyzerSqlite import AnalyzerSqlite
|
|
||||||
from hts.BuySellChecker import BuySellChecker
|
|
||||||
from hts.HTS import HTS
|
|
||||||
|
|
||||||
class Bithumb_daily(HTS):
|
|
||||||
|
|
||||||
RESOURCE_PATH = None
|
|
||||||
buySellChecker = None
|
|
||||||
analyzerSqlite = None
|
|
||||||
|
|
||||||
def __init__(self, RESOURCE_PATH):
|
|
||||||
super().__init__(RESOURCE_PATH)
|
|
||||||
self.RESOURCE_PATH = RESOURCE_PATH
|
|
||||||
|
|
||||||
con_key = "946dd0b0e6f8ad411144cd33f09518d3" # 본인의 Connect Key를 입력한다.
|
|
||||||
sec_key = "56b2a3cdd9fe3a82aa3f38c97c161125" # 본인의 Secret Key를 입력한다.
|
|
||||||
|
|
||||||
# bithumb api에 연결한 클라스 객체를 선언한다.
|
|
||||||
self.bithumb = pybithumb.Bithumb(con_key, sec_key)
|
|
||||||
|
|
||||||
self.buySellChecker = BuySellChecker()
|
|
||||||
self.analyzerSqlite = AnalyzerSqlite()
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
def bull_market(self, df, ticker):
|
|
||||||
m5 = df['close'].rolling(5).mean()
|
|
||||||
last_m5 = m5[-2]
|
|
||||||
|
|
||||||
price = pybithumb.get_current_price(ticker)
|
|
||||||
|
|
||||||
if price > last_m5:
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
def append(self, df, stock):
|
|
||||||
for i in range(len(df)):
|
|
||||||
stock['PRICE'].append(
|
|
||||||
{
|
|
||||||
"ymd": df.index[i].strftime('%Y.%m.%d'),
|
|
||||||
"close": df['close'][i],
|
|
||||||
"diff": 0,
|
|
||||||
"open": df['open'][i],
|
|
||||||
"high": df['high'][i],
|
|
||||||
"low": df['low'][i],
|
|
||||||
"volume": df['volume'][i],
|
|
||||||
"avg3": -1,
|
|
||||||
"avg4": -1,
|
|
||||||
"avg5": -1,
|
|
||||||
"avg6": -1,
|
|
||||||
"avg10": -1,
|
|
||||||
"avg12": -1,
|
|
||||||
"avg20": -1,
|
|
||||||
"avg36": -1,
|
|
||||||
"avg40": -1,
|
|
||||||
"avg48": -1,
|
|
||||||
"avg60": -1,
|
|
||||||
"avg120": -1,
|
|
||||||
"avg200": -1,
|
|
||||||
"avg240": -1,
|
|
||||||
"avg300": -1,
|
|
||||||
"disparity_avg5": -1,
|
|
||||||
"disparity_avg10": -1,
|
|
||||||
"disparity_avg20": -1,
|
|
||||||
"disparity_avg60": -1,
|
|
||||||
"disparity_avg120": -1,
|
|
||||||
"bolingerband_upper": -1,
|
|
||||||
"bolingerband_lower": -1,
|
|
||||||
"bolingerband_middle": -1,
|
|
||||||
"envelope_upper": -1,
|
|
||||||
"envelope_lower": -1,
|
|
||||||
"envelope_middle": -1,
|
|
||||||
"ichimokucloud_changeLine": -1,
|
|
||||||
"ichimokucloud_baseLine": -1,
|
|
||||||
"ichimokucloud_leadingSpan1": -1,
|
|
||||||
"ichimokucloud_leadingSpan2": -1,
|
|
||||||
"stochastic_fast_k": -1,
|
|
||||||
"stochastic_slow_k": -1,
|
|
||||||
"stochastic_slow_d": -1,
|
|
||||||
"rsi": -1,
|
|
||||||
"rsis": -1,
|
|
||||||
"macd": -1,
|
|
||||||
"macds": -1,
|
|
||||||
"macdo": -1,
|
|
||||||
})
|
|
||||||
return
|
|
||||||
|
|
||||||
def analyze (self, stock, days=120):
|
|
||||||
stock["PRICE"] = sorted(stock["PRICE"], key=lambda x: x['ymd'])
|
|
||||||
self.analyzerSqlite.get_moving_average(stock["PRICE"])
|
|
||||||
|
|
||||||
# 이동 평균을 이용한 이격도 계산
|
|
||||||
self.analyzerSqlite.get_disparity(stock["PRICE"])
|
|
||||||
|
|
||||||
self.analyzerSqlite.ichimokuCloud.analyze(stock)
|
|
||||||
self.analyzerSqlite.stochastic.analyze(stock)
|
|
||||||
self.analyzerSqlite.bolingerBand.analyze(stock)
|
|
||||||
self.analyzerSqlite.envelope.analyze(stock)
|
|
||||||
self.analyzerSqlite.rsi.analyze(stock)
|
|
||||||
self.analyzerSqlite.macd.analyze(stock)
|
|
||||||
|
|
||||||
result = {
|
|
||||||
"ymd": [],
|
|
||||||
"open": [],
|
|
||||||
"close": [],
|
|
||||||
"high": [],
|
|
||||||
"low": [],
|
|
||||||
"avg3": [],
|
|
||||||
"avg4": [],
|
|
||||||
"avg5": [],
|
|
||||||
"avg6": [],
|
|
||||||
"avg10": [],
|
|
||||||
"avg12": [],
|
|
||||||
"avg20": [],
|
|
||||||
"avg36": [],
|
|
||||||
"avg40": [],
|
|
||||||
"avg48": [],
|
|
||||||
"avg60": [],
|
|
||||||
"avg120": [],
|
|
||||||
"avg200": [],
|
|
||||||
"avg240": [],
|
|
||||||
"avg300": [],
|
|
||||||
"disparity_avg5": [],
|
|
||||||
"disparity_avg20": [],
|
|
||||||
"disparity_avg60": [],
|
|
||||||
"disparity_avg120": [],
|
|
||||||
"disparity": [],
|
|
||||||
"disparity_type": [],
|
|
||||||
"envelope_upper": [],
|
|
||||||
"envelope_lower": [],
|
|
||||||
"envelope_middle": [],
|
|
||||||
"rsi": [],
|
|
||||||
"rsis": [],
|
|
||||||
"macd": [],
|
|
||||||
"macds": [],
|
|
||||||
"slow_k": [],
|
|
||||||
"slow_d": [],
|
|
||||||
"buy": [],
|
|
||||||
"sell": [],
|
|
||||||
}
|
|
||||||
for item in stock['PRICE']:
|
|
||||||
result["ymd"].append(item['ymd'])
|
|
||||||
result["open"].append(item['open'])
|
|
||||||
result["close"].append(item['close'])
|
|
||||||
result["high"].append(item['high'])
|
|
||||||
result["low"].append(item['low'])
|
|
||||||
result["avg3"].append(item['avg3'])
|
|
||||||
result["avg4"].append(item['avg4'])
|
|
||||||
result["avg5"].append(item['avg5'])
|
|
||||||
result["avg6"].append(item['avg6'])
|
|
||||||
result["avg10"].append(item['avg10'])
|
|
||||||
result["avg12"].append(item['avg12'])
|
|
||||||
result["avg20"].append(item['avg20'])
|
|
||||||
result["avg36"].append(item['avg36'])
|
|
||||||
result["avg40"].append(item['avg40'])
|
|
||||||
result["avg48"].append(item['avg48'])
|
|
||||||
result["avg60"].append(item['avg60'])
|
|
||||||
result["avg120"].append(item['avg120'])
|
|
||||||
result["avg200"].append(item['avg200'])
|
|
||||||
result["avg240"].append(item['avg240'])
|
|
||||||
result["avg300"].append(item['avg300'])
|
|
||||||
result["disparity_avg5"].append(item['disparity_avg5'])
|
|
||||||
result["disparity_avg20"].append(item['disparity_avg20'])
|
|
||||||
result["disparity_avg60"].append(item['disparity_avg60'])
|
|
||||||
result["disparity_avg120"].append(item['disparity_avg120'])
|
|
||||||
result['disparity'].append(max(item['disparity_avg5'], item['disparity_avg20'], item['disparity_avg60']) - min(item['disparity_avg5'], item['disparity_avg20'], item['disparity_avg60']))
|
|
||||||
if item['disparity_avg60'] < item['disparity_avg20'] < item['disparity_avg5']:
|
|
||||||
result['disparity_type'].append(1)
|
|
||||||
elif item['disparity_avg5'] < item['disparity_avg20'] < item['disparity_avg60']:
|
|
||||||
result['disparity_type'].append(-1)
|
|
||||||
else:
|
|
||||||
result['disparity_type'].append(0)
|
|
||||||
result["envelope_upper"].append(item['envelope_upper'])
|
|
||||||
result["envelope_lower"].append(item['envelope_lower'])
|
|
||||||
result["envelope_middle"].append(item['envelope_middle'])
|
|
||||||
result["rsi"].append(item['rsi'])
|
|
||||||
result["rsis"].append(item['rsis'])
|
|
||||||
result["macd"].append(item['macd'])
|
|
||||||
result["macds"].append(item['macds'])
|
|
||||||
result["slow_k"].append(item['stochastic_slow_k'])
|
|
||||||
result["slow_d"].append(item['stochastic_slow_d'])
|
|
||||||
result["buy"].append(-1)
|
|
||||||
result["sell"].append(-1)
|
|
||||||
|
|
||||||
data = pd.DataFrame(result)
|
|
||||||
df_final_time = pd.DatetimeIndex(result['ymd'])
|
|
||||||
data.index = df_final_time
|
|
||||||
|
|
||||||
data = data.astype(
|
|
||||||
{
|
|
||||||
'open': 'int',
|
|
||||||
'high': 'int',
|
|
||||||
'low': 'int',
|
|
||||||
'close': 'int',
|
|
||||||
'avg3': 'float',
|
|
||||||
'avg4': 'float',
|
|
||||||
'avg5': 'float',
|
|
||||||
'avg6': 'float',
|
|
||||||
'avg10': 'float',
|
|
||||||
'avg12': 'float',
|
|
||||||
'avg20': 'float',
|
|
||||||
'avg36': 'float',
|
|
||||||
'avg40': 'float',
|
|
||||||
'avg48': 'float',
|
|
||||||
'avg60': 'float',
|
|
||||||
'avg120': 'float',
|
|
||||||
'avg200': 'float',
|
|
||||||
'avg240': 'float',
|
|
||||||
'avg300': 'float',
|
|
||||||
'disparity_avg5': 'float',
|
|
||||||
'disparity_avg20': 'float',
|
|
||||||
'disparity_avg60': 'float',
|
|
||||||
'disparity_avg120': 'float',
|
|
||||||
'buy': 'int',
|
|
||||||
'sell': 'int',
|
|
||||||
'slow_k': 'float',
|
|
||||||
'slow_d': 'float',
|
|
||||||
'macd': 'float',
|
|
||||||
'macds': 'float',
|
|
||||||
'envelope_upper': 'float',
|
|
||||||
'envelope_lower': 'float',
|
|
||||||
'envelope_middle': 'float',
|
|
||||||
'rsi': 'float',
|
|
||||||
'rsis': 'float'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
scaler = StandardScaler()
|
|
||||||
low_df = pd.DataFrame(data['low'])
|
|
||||||
low_df.index = [c for c in range(len(low_df))]
|
|
||||||
low_std = scaler.fit_transform(data['low'].values.reshape(-1, 1))
|
|
||||||
low_std = pd.DataFrame(low_std, columns=['low_std'])
|
|
||||||
|
|
||||||
min_df = pd.DataFrame({'open': data['open'].to_list(), 'close': data['close'].to_list()})
|
|
||||||
min_df['min_std'] = min_df.min(axis=1)
|
|
||||||
min_df.index = [c for c in range(len(min_df))]
|
|
||||||
min_std = scaler.fit_transform(min_df['min_std'].values.reshape(-1, 1))
|
|
||||||
min_std = pd.DataFrame(min_std, columns=['min_std'])
|
|
||||||
|
|
||||||
line_fitter = LinearRegression()
|
|
||||||
size = len(data["close"])
|
|
||||||
gradients_low = []
|
|
||||||
gradients_avg5 = []
|
|
||||||
gradients_avg20 = []
|
|
||||||
gradients_avg60 = []
|
|
||||||
|
|
||||||
for i in range(size):
|
|
||||||
coef_low = -999
|
|
||||||
coef_avg5 = -999
|
|
||||||
coef_avg20 = -999
|
|
||||||
coef_avg60 = -999
|
|
||||||
|
|
||||||
if i > 0:
|
|
||||||
l = days if i >= days else i
|
|
||||||
x = pd.DataFrame([c for c in range(i - l, i + 1)])
|
|
||||||
y = pd.DataFrame(low_std.values.tolist()[i - l:i + 1])
|
|
||||||
line_fitter.fit(x.values.reshape(-1, 1), y)
|
|
||||||
coef_low = line_fitter.coef_[0][0]
|
|
||||||
|
|
||||||
l = 5 if i >= 5 else i
|
|
||||||
x = pd.DataFrame([c for c in range(i - l, i + 1)])
|
|
||||||
y = pd.DataFrame(min_std.values.tolist()[i - l:i + 1])
|
|
||||||
line_fitter.fit(x.values.reshape(-1, 1), y)
|
|
||||||
coef_avg5 = line_fitter.coef_[0][0]
|
|
||||||
|
|
||||||
l = 20 if i >= 20 else i
|
|
||||||
x = pd.DataFrame([c for c in range(i - l, i + 1)])
|
|
||||||
y = pd.DataFrame(min_std.values.tolist()[i - l:i + 1])
|
|
||||||
line_fitter.fit(x.values.reshape(-1, 1), y)
|
|
||||||
coef_avg20 = line_fitter.coef_[0][0]
|
|
||||||
|
|
||||||
l = 60 if i >= 60 else i
|
|
||||||
x = pd.DataFrame([c for c in range(i - l, i + 1)])
|
|
||||||
y = pd.DataFrame(min_std.values.tolist()[i - l:i + 1])
|
|
||||||
line_fitter.fit(x.values.reshape(-1, 1), y)
|
|
||||||
coef_avg60 = line_fitter.coef_[0][0]
|
|
||||||
|
|
||||||
gradients_low.append(coef_low)
|
|
||||||
gradients_avg5.append(coef_avg5)
|
|
||||||
gradients_avg20.append(coef_avg20)
|
|
||||||
gradients_avg60.append(coef_avg60)
|
|
||||||
|
|
||||||
gradients_low_df = pd.DataFrame(gradients_low, columns=['gradients_low'])
|
|
||||||
gradients_avg5_df = pd.DataFrame(gradients_avg5, columns=['gradients_avg5'])
|
|
||||||
gradients_avg20_df = pd.DataFrame(gradients_avg20, columns=['gradients_avg20'])
|
|
||||||
gradients_avg60_df = pd.DataFrame(gradients_avg60, columns=['gradients_avg60'])
|
|
||||||
|
|
||||||
gradients_low_df.index = df_final_time
|
|
||||||
gradients_avg5_df.index = df_final_time
|
|
||||||
gradients_avg20_df.index = df_final_time
|
|
||||||
gradients_avg60_df.index = df_final_time
|
|
||||||
|
|
||||||
data = data.merge(gradients_low_df, left_index=True, right_index=True)
|
|
||||||
data = data.merge(gradients_avg5_df, left_index=True, right_index=True)
|
|
||||||
data = data.merge(gradients_avg20_df, left_index=True, right_index=True)
|
|
||||||
data = data.merge(gradients_avg60_df, left_index=True, right_index=True)
|
|
||||||
|
|
||||||
return data
|
|
||||||
|
|
||||||
def writeFile(self, dirName, ticker, data, bsLine, today):
|
|
||||||
if bsLine is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
# 어제 데이터는 지운다.
|
|
||||||
buy_line = bsLine['buy']
|
|
||||||
buy_weight_line = bsLine['buy_weight']
|
|
||||||
sell_line = bsLine['sell']
|
|
||||||
|
|
||||||
buy_size = []
|
|
||||||
buy_colors = []
|
|
||||||
for i in range(len(buy_line)):
|
|
||||||
if buy_line[i] < 0:
|
|
||||||
buy_colors.append("#ffffff")
|
|
||||||
buy_line[i] = nan
|
|
||||||
buy_size.append(0)
|
|
||||||
else:
|
|
||||||
buy_colors.append("#B2028C")
|
|
||||||
buy_size.append(10 + (0.1 * buy_weight_line[i]))
|
|
||||||
|
|
||||||
sell_colors = []
|
|
||||||
for i in range(len(sell_line)):
|
|
||||||
if sell_line[i] < 0:
|
|
||||||
sell_colors.append("#ffffff")
|
|
||||||
sell_line[i] = nan
|
|
||||||
else:
|
|
||||||
sell_colors.append("#00ced1")
|
|
||||||
|
|
||||||
# 그래프를 설정한다.
|
|
||||||
buy_check = go.Scatter(x=data['ymd'], y=buy_line, mode='markers', name="buy", marker=dict(size=buy_size, color=buy_colors, line_width=0))
|
|
||||||
sell_check = go.Scatter(x=data['ymd'], y=sell_line, mode='markers', name="sell", marker=dict(size=14, color=sell_colors, line_width=0))
|
|
||||||
envelope_upper = go.Scatter(x=data['ymd'], y=data["envelope_upper"], name="upper", line_color='#000000')
|
|
||||||
envelope_middle = go.Scatter(x=data['ymd'], y=data["envelope_middle"], name="middle", line_color='#927786')
|
|
||||||
envelope_lower = go.Scatter(x=data['ymd'], y=data["envelope_lower"], name="lower", line_color='#000000')
|
|
||||||
|
|
||||||
avg5 = go.Scatter(x=data['ymd'], y=data["avg5"], name="avg5", line_color='#6C2507')
|
|
||||||
avg20 = go.Scatter(x=data['ymd'], y=data["avg20"], name="avg20", line_color='#f84c43')
|
|
||||||
avg60 = go.Scatter(x=data['ymd'], y=data["avg60"], name="avg60", line_color='#f89543')
|
|
||||||
candle_stick = go.Candlestick(x=data['ymd'], open=data['open'], high=data['high'], low=data['low'], close=data['close'], increasing_line_color='red', decreasing_line_color='blue', showlegend=False)
|
|
||||||
|
|
||||||
macd_line = go.Scatter(x=data['ymd'], y=data["macd"], line=dict(color='red', width=2), name='macd')
|
|
||||||
macd_s_line = go.Scatter(x=data['ymd'], y=data["macds"], line=dict(dash='dashdot', color='black', width=2), name='macds')
|
|
||||||
|
|
||||||
# fast_k_line = go.Scatter(x=hts['date'], y=hts["fast_k"], mode='lines', name='fast_k')
|
|
||||||
slow_k_line = go.Scatter(x=data['ymd'], y=data["slow_k"], line=dict(color='red', width=2), name='slow_k')
|
|
||||||
slow_d_line = go.Scatter(x=data['ymd'], y=data["slow_d"], line=dict(dash='dashdot', color='black', width=2), name='slow_d')
|
|
||||||
|
|
||||||
rsi_line = go.Scatter(x=data['ymd'], y=data["rsi"], line=dict(color='red', width=2), name='rsi')
|
|
||||||
rsis_line = go.Scatter(x=data['ymd'], y=data["rsis"], line=dict(dash='dashdot', color='black', width=2), name='rsis')
|
|
||||||
|
|
||||||
disparity_avg5 = go.Scatter(x=data['ymd'], y=data["disparity_avg5"], name="disparity_avg5", line_color='#8F8203')
|
|
||||||
disparity_avg20 = go.Scatter(x=data['ymd'], y=data["disparity_avg20"], name="disparity_avg20", line_color='#ff00ff')
|
|
||||||
disparity_avg60 = go.Scatter(x=data['ymd'], y=data["disparity_avg60"], name="disparity_avg60", line_color='#1469F4')
|
|
||||||
|
|
||||||
candle_data = [candle_stick, avg5, avg20, avg60, envelope_upper, envelope_middle, envelope_lower, buy_check, sell_check]
|
|
||||||
disparity_data = [disparity_avg5, disparity_avg20, disparity_avg60]
|
|
||||||
macd_data = [macd_line, macd_s_line]
|
|
||||||
stochastic_data = [slow_k_line, slow_d_line]
|
|
||||||
rsi_data = [rsi_line, rsis_line]
|
|
||||||
|
|
||||||
# 그래프를 그린다.
|
|
||||||
"""
|
|
||||||
fig = go.Figure(data=candle_data)
|
|
||||||
fig.update_layout(title=stock_code + "_" + given_day)
|
|
||||||
fig.show()
|
|
||||||
"""
|
|
||||||
|
|
||||||
fig = subplots.make_subplots(
|
|
||||||
rows=5, cols=1,
|
|
||||||
subplot_titles=("MACD", "RSI", "스토캐스틱", '이격도', '캔들'),
|
|
||||||
#specs=[[{}], [{}], [{}], [{}], [{}], [{}]],
|
|
||||||
shared_xaxes=True, horizontal_spacing=0.03, vertical_spacing=0.01,
|
|
||||||
row_heights=[200, 200, 200, 200, 750]
|
|
||||||
)
|
|
||||||
for trace in macd_data:
|
|
||||||
fig.append_trace(trace, 1, 1)
|
|
||||||
for trace in rsi_data:
|
|
||||||
fig.append_trace(trace, 2, 1)
|
|
||||||
for trace in stochastic_data:
|
|
||||||
fig.append_trace(trace, 3, 1)
|
|
||||||
for trace in disparity_data:
|
|
||||||
fig.append_trace(trace, 4, 1)
|
|
||||||
for trace in candle_data:
|
|
||||||
fig.append_trace(trace, 5, 1)
|
|
||||||
|
|
||||||
df = pd.DataFrame(bsLine)
|
|
||||||
df = df.fillna(-1)
|
|
||||||
buy_count = len(df.loc[df["buy"] > 0])
|
|
||||||
sell_count = len(df.loc[df["sell"] > 0])
|
|
||||||
|
|
||||||
fig.update_layout(height=1700, title="_" + str(buy_count)+","+str(sell_count))
|
|
||||||
fig['layout'].update()
|
|
||||||
|
|
||||||
fileName = "%s/%s_%s.html" % (dirName, ticker, today)
|
|
||||||
po.write_html(fig, file=fileName, auto_open=False)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
def getBalance(self, ticker):
|
|
||||||
tmp = self.bithumb.get_balance(ticker)
|
|
||||||
return tmp[2]
|
|
||||||
|
|
||||||
def exist_buy(self, ticker, log_filename):
|
|
||||||
if os.path.exists(log_filename):
|
|
||||||
log_file = open(log_filename, 'r', )
|
|
||||||
reader = csv.reader(log_file)
|
|
||||||
for line in reader:
|
|
||||||
if line[2] == ticker:
|
|
||||||
log_file.close()
|
|
||||||
return True
|
|
||||||
log_file.close()
|
|
||||||
return False
|
|
||||||
|
|
||||||
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 for i in range(size)]
|
|
||||||
bsLine['sell'] = [-1 for i in range(size)]
|
|
||||||
bsLine['sell_weight'] = [-1 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:
|
|
||||||
buy = data['low'][i]
|
|
||||||
data['buy'][i] = buy
|
|
||||||
bsLine['buy'][i] = buy
|
|
||||||
bsLine['buy_weight'][i] = 10
|
|
||||||
|
|
||||||
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
|
|
||||||
):
|
|
||||||
buy = data['low'][i]
|
|
||||||
data['buy'][i] = buy
|
|
||||||
bsLine['buy'][i] = buy
|
|
||||||
bsLine['buy_weight'][i] = 10
|
|
||||||
|
|
||||||
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:
|
|
||||||
buy = data['low'][i]
|
|
||||||
data['buy'][i] = buy
|
|
||||||
bsLine['buy'][i] = buy
|
|
||||||
bsLine['buy_weight'][i] = 10
|
|
||||||
|
|
||||||
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:
|
|
||||||
buy = data['low'][i]
|
|
||||||
data['buy'][i] = buy
|
|
||||||
bsLine['buy'][i] = buy
|
|
||||||
bsLine['buy_weight'][i] = 10
|
|
||||||
|
|
||||||
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:
|
|
||||||
buy = data['low'][i]
|
|
||||||
data['buy'][i] = buy
|
|
||||||
bsLine['buy'][i] = buy
|
|
||||||
bsLine['buy_weight'][i] = 10
|
|
||||||
|
|
||||||
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:
|
|
||||||
buy = data['low'][i]
|
|
||||||
data['buy'][i] = buy
|
|
||||||
bsLine['buy'][i] = buy
|
|
||||||
bsLine['buy_weight'][i] = 10
|
|
||||||
|
|
||||||
# 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] = 10
|
|
||||||
|
|
||||||
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):
|
|
||||||
buy = data['low'][i]
|
|
||||||
data['buy'][i] = buy
|
|
||||||
bsLine['buy'][i] = buy
|
|
||||||
bsLine['buy_weight'][i] = 15
|
|
||||||
|
|
||||||
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]:
|
|
||||||
buy = data['low'][i]
|
|
||||||
data['buy'][i] = buy
|
|
||||||
bsLine['buy'][i] = buy
|
|
||||||
bsLine['buy_weight'][i] = 15
|
|
||||||
|
|
||||||
return bsLine, data
|
|
||||||
|
|
||||||
def buyRealTime(self, ticker, analyzed_day=120, isRealTime=False):
|
|
||||||
|
|
||||||
stock = {"CODE": ticker, "NAME": ticker, "PRICE": []}
|
|
||||||
df = pybithumb.get_ohlcv(ticker)
|
|
||||||
if df is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
close = pybithumb.get_current_price(ticker)
|
|
||||||
|
|
||||||
size = len(df)
|
|
||||||
df['close'][size - 1] = close
|
|
||||||
if close < df['low'][size - 1]:
|
|
||||||
df['low'][size - 1] = close
|
|
||||||
if df['high'][size - 1] < close:
|
|
||||||
df['high'][size - 1] = close
|
|
||||||
self.append(df, stock)
|
|
||||||
|
|
||||||
data = self.analyze(stock, analyzed_day)
|
|
||||||
|
|
||||||
# 분석일 데이터만 활용한다 (이전 데이터는 제거)
|
|
||||||
data.drop(data.index[:len(data) - analyzed_day], inplace=True)
|
|
||||||
|
|
||||||
bsLine, data = self.checkWithEnvelope(data, analyzed_day, isRealTime=isRealTime)
|
|
||||||
print(ticker, "/", datetime.now().strftime('%Y-%m-%d %H:%M:%S'), "/", data['close'][len(data['close'])-1], "/", data['slow_k'][len(data['slow_k'])-1])
|
|
||||||
|
|
||||||
# 그래프를 그린다.
|
|
||||||
if len(data.index) > 10:
|
|
||||||
today = datetime.today().strftime('%Y%m%d')
|
|
||||||
log_filename = os.path.join(RESOURCE_PATH, 'analysis', '', today + '.log')
|
|
||||||
|
|
||||||
# realtime이고, 5분이내 매수 기록이 없다면
|
|
||||||
if isRealTime and not self.exist_buy(ticker, log_filename):
|
|
||||||
if max(bsLine['buy'][len(bsLine['buy']) - 2:]) > 100:
|
|
||||||
balance = self.getBalance(ticker)
|
|
||||||
count = round((balance * (bsLine['buy_weight'][len(bsLine['buy_weight'])-1]/100)) / bsLine['buy'][len(bsLine['buy'])-1], 2)
|
|
||||||
order = self.bithumb.buy_limit_order(ticker, bsLine['buy'][len(bsLine['buy'])-1], count)
|
|
||||||
# order: ('bid', 'BTC', 'C0101000000322993432', 'KRW')
|
|
||||||
|
|
||||||
with open(log_filename, 'a', newline='', encoding='utf-8') as log_file:
|
|
||||||
wr = csv.writer(log_file)
|
|
||||||
wr.writerow([datetime.now().strftime('%Y-%m-%d %H:%M:%S'), order[0], order[1], order[2], order[3]])
|
|
||||||
|
|
||||||
dirName = os.path.join(RESOURCE_PATH, 'analysis', '')
|
|
||||||
self.writeFile(dirName, ticker, data, bsLine, datetime.now().strftime('%Y%m%d %H%M%S'), 'buy')
|
|
||||||
else:
|
|
||||||
dirName = os.path.join(RESOURCE_PATH, 'analysis', '')
|
|
||||||
self.writeFile(dirName, ticker, data, bsLine, datetime.now().strftime('%Y%m%d %H%M%S'))
|
|
||||||
|
|
||||||
return bsLine, data
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
|
|
||||||
PROJECT_HOME = os.path.join(os.path.dirname(os.path.join(os.path.dirname(__file__))))
|
|
||||||
RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources")
|
|
||||||
|
|
||||||
if not os.path.exists(os.path.join(RESOURCE_PATH, 'analysis', '')):
|
|
||||||
os.mkdir(os.path.join(RESOURCE_PATH, 'analysis', ''))
|
|
||||||
dirName = os.path.join(RESOURCE_PATH, 'analysis', '')
|
|
||||||
if not os.path.exists(dirName):
|
|
||||||
os.mkdir(dirName)
|
|
||||||
|
|
||||||
bithumb = Bithumb_daily(RESOURCE_PATH)
|
|
||||||
|
|
||||||
tickers = ['XRP', 'BTC', 'SOL']
|
|
||||||
analyzed_day = 120
|
|
||||||
isRealTime = False
|
|
||||||
if isRealTime:
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
for ticker in tickers:
|
|
||||||
bithumb.buyRealTime(ticker, analyzed_day, isRealTime)
|
|
||||||
except:
|
|
||||||
time.sleep(30)
|
|
||||||
continue
|
|
||||||
time.sleep(10)
|
|
||||||
else:
|
|
||||||
for ticker in tickers:
|
|
||||||
bithumb.buyRealTime(ticker, analyzed_day, isRealTime)
|
|
||||||
Reference in New Issue
Block a user