import pandas as pd import jwt import uuid import time import requests import json import hashlib from urllib.parse import urlencode class HTS: bithumb = None #accessKey = "a5d33ce55f598185d37cd26272341b7b965c31a59457f7" # 본인의 Connect Key를 입력한다. #secretKey = "ODBiYWFmNWE2MTkwYjdhMTNhZTM1YjU5OGY4OGE2MGNkNDY2NzMzMjE2Nzc5NDVlMzBhMDk3NTNmM2M2Mg==" # 본인의 Secret Key를 입력한다. accessKey = "1b10570cfaacb728fbdbb0b289c367e95ed937b1bd4157" # 본인의 Connect Key를 입력한다. secretKey = "MGU0NzYzMzQyNTJhMDk2MjUxMGFmZWFjYjkyNThlYWJiNmIzOGNjODZjZWE1NmQyMzdiN2JiNDM1Njg1MA==" # 본인의 Secret Key를 입력한다. apiUrl = 'https://api.bithumb.com' def __init__(self): #self.bithumb = pybithumb.Bithumb(self.con_key, self.sec_key) self.bithumb = None #self.accessKey = "a5d33ce55f598185d37cd26272341b7b965c31a59457f7" # 본인의 Connect Key를 입력한다. #self.secretKey = "ODBiYWFmNWE2MTkwYjdhMTNhZTM1YjU5OGY4OGE2MGNkNDY2NzMzMjE2Nzc5NDVlMzBhMDk3NTNmM2M2Mg==" # 본인의 Secret Key를 입력한다. self.accessKey = "1b10570cfaacb728fbdbb0b289c367e95ed937b1bd4157" # 본인의 Connect Key를 입력한다. self.secretKey = "MGU0NzYzMzQyNTJhMDk2MjUxMGFmZWFjYjkyNThlYWJiNmIzOGNjODZjZWE1NmQyMzdiN2JiNDM1Njg1MA==" # 본인의 Secret Key를 입력한다. self.apiUrl = 'https://api.bithumb.com' return def append(self, stock, df=None, data_1=None): if df is not None: for i in range(len(df)): stock['PRICE'].append( { "ymd": df.index[i], "close": df['close'].iloc[i], "diff": 0, "open": df['open'].iloc[i], "high": df['high'].iloc[i], "low": df['low'].iloc[i], "volume": df['volume'].iloc[i], "avg5": -1, "avg20": -1, "avg60": -1, "avg120": -1, "avg240": -1, "avg480": -1, "bolingerband_upper": -1, "bolingerband_lower": -1, "bolingerband_middle": -1, "bolingerband_bwi": -1, "ichimokucloud_changeLine": -1, "ichimokucloud_baseLine": -1, "ichimokucloud_leadingSpan1": -1, "ichimokucloud_leadingSpan2": -1, "stochastic_fast_k_1": -1, "stochastic_slow_k_1": -1, "stochastic_slow_d_1": -1, "stochastic_fast_k_2": -1, "stochastic_slow_k_2": -1, "stochastic_slow_d_2": -1, "stochastic_fast_k_3": -1, "stochastic_slow_k_3": -1, "stochastic_slow_d_3": -1, "rsi": -1, "rsis": -1, "macd": -1, "macds": -1, "macdo": -1, "nor_macd": -1, "nor_macds": -1, "nor_macdo": -1, }) if data_1 is not None: stock['PRICE'].append( { "ymd": data_1.index[-1], "close": data_1['close'].iloc[-1], "diff": 0, "open": data_1['open'].iloc[-1], "high": data_1['high'].iloc[-1], "low": data_1['low'].iloc[-1], "volume": data_1['volume'].iloc[-1], "avg5": -1, "avg20": -1, "avg60": -1, "avg120": -1, "avg240": -1, "avg480": -1, "bolingerband_upper": -1, "bolingerband_lower": -1, "bolingerband_middle": -1, "bolingerband_bwi": -1, "bolingerband_nor_bwi": -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": -1, "stochastic_slow_k_1": -1, "stochastic_slow_d_1": -1, "stochastic_fast_k_2": -1, "stochastic_slow_k_2": -1, "stochastic_slow_d_2": -1, "stochastic_fast_k_3": -1, "stochastic_slow_k_3": -1, "stochastic_slow_d_3": -1, "rsi": -1, "rsis": -1, "macd": -1, "macds": -1, "macdo": -1, "nor_macd": -1, "nor_macds": -1, "nor_macdo": -1, }) return def getCoinRawData(self, ticker_code, minute=None, day=False, week=False, month=False, to=None, endpoint='/v1/candles'): url = None if minute == 0: # 현재가 정보 url = (self.apiUrl + "/v1/ticker?markets=KRW-{}").format(ticker_code) headers = {"accept": "application/json"} response = requests.get(url, headers=headers) json_data = json.loads(response.text) df_temp = pd.DataFrame(json_data) if 'trade_date_kst' not in df_temp or 'trade_time_kst' not in df_temp: return None df = pd.DataFrame() df['datetime'] = pd.to_datetime(df_temp['trade_date_kst'], format='%Y-%m-%dT%H:%M:%S') df['open'] = df_temp['opening_price'] df['close'] = df_temp['trade_price'] df['high'] = df_temp['high_price'] df['low'] = df_temp['low_price'] df['volume'] = df_temp['trade_volume'] df = df.set_index('datetime') df = df.astype(float) df["datetime"] = df.index else: # 분봉 if minute is not None and minute in {1, 3, 5, 10, 15, 30, 60, 240}: if to is None: url = (self.apiUrl + endpoint + "/minutes/{}?market=KRW-{}&count=3000").format(minute, ticker_code) else: url = (self.apiUrl + endpoint + "/minutes/{}?market=KRW-{}&count=3000&to={}").format(minute, ticker_code, to) if day: if to is None: url = (self.apiUrl + endpoint + "/days?market=KRW-{}&count=3000").format(ticker_code) else: url = (self.apiUrl + endpoint + "/days?market=KRW-{}&count=3000&to={}").format(ticker_code, to) if week: if to is None: url = (self.apiUrl + endpoint + "/weeks?market=KRW-{}&count=3000").format(ticker_code) else: url = (self.apiUrl + endpoint + "/weeks?market=KRW-{}&count=3000&to={}").format(ticker_code, to) if month: if to is None: url = (self.apiUrl + endpoint + "/months?market=KRW-{}&count=3000").format(ticker_code) else: url = (self.apiUrl + endpoint + "/months?market=KRW-{}&count=3000&to={}").format(ticker_code, to) if url is None: return None headers = {"accept": "application/json"} response = requests.get(url, headers=headers) json_data = json.loads(response.text) df_temp = pd.DataFrame(json_data) if 'candle_date_time_kst' not in df_temp: return None df = pd.DataFrame() #df.columns = ['datetime', 'open', 'close', 'high', 'low', 'volume'] #df['datetime'] = pd.to_datetime(df_temp['candle_date_time_kst']) df['datetime'] = pd.to_datetime(df_temp['candle_date_time_kst'], format='%Y-%m-%dT%H:%M:%S') df['open'] = df_temp['opening_price'] df['close'] = df_temp['trade_price'] df['high'] = df_temp['high_price'] df['low'] = df_temp['low_price'] df['volume'] = df_temp['candle_acc_trade_volume'] df = df.set_index('datetime') df = df.astype(float) df["datetime"] = df.index if df is None: return None return df def getTickerList(self): url = "https://api.bithumb.com/v1/market/all?isDetails=false" headers = {"accept": "application/json"} response = requests.get(url, headers=headers) tickets = response.json() return tickets def getVirtual_asset_warning(self): url = "https://api.bithumb.com/v1/market/virtual_asset_warning" headers = {"accept": "application/json"} response = requests.get(url, headers=headers) warning_list = response.json() return warning_list # 거래대금이 많은 순으로 코인리스트를 얻는다. def getTopCoinList(self, interval, top): return # 현재 가격 얻어오기 def getCurrentPrice(self, ticker_code, endpoint='/v1/ticker'): headers = {"accept": "application/json"} url = (self.apiUrl + endpoint + "?markets=KRW-{}").format(ticker_code) response = requests.get(url, headers=headers) ticker_state = response.json() return ticker_state # 잔고 가져오기 def getBalances(self, ticker_code=None, endpoint='/v1/accounts'): payload = { 'access_key': self.accessKey, 'nonce': str(uuid.uuid4()), 'timestamp': round(time.time() * 1000) } jwt_token = jwt.encode(payload, self.secretKey) authorization_token = 'Bearer {}'.format(jwt_token) headers = { 'Authorization': authorization_token } response = requests.get(self.apiUrl + endpoint, headers=headers) balances = response.json() """ [ {'currency': 'P', 'balance': '78290', 'locked': '0', 'avg_buy_price': '0', 'avg_buy_price_modified': False, 'unit_currency': 'KRW'}, {'currency': 'KRW', 'balance': '4218.401653', 'locked': '0', 'avg_buy_price': '0', 'avg_buy_price_modified': False, 'unit_currency': 'KRW'}, {'currency': 'XRP', 'balance': '13069.27647861', 'locked': '0', 'avg_buy_price': '1917', 'avg_buy_price_modified': False, 'unit_currency': 'KRW'}, {'currency': 'ADA', 'balance': '6941.65484013', 'locked': '0', 'avg_buy_price': '1260', 'avg_buy_price_modified': False, 'unit_currency': 'KRW'}, {'currency': 'BSV', 'balance': '0.00005656', 'locked': '0', 'avg_buy_price': '65450', 'avg_buy_price_modified': False, 'unit_currency': 'KRW'}, {'currency': 'SAND', 'balance': '0.00001158', 'locked': '0', 'avg_buy_price': '544.8', 'avg_buy_price_modified': False, 'unit_currency': 'KRW'}, {'currency': 'AVAX', 'balance': '26.43960509', 'locked': '0', 'avg_buy_price': '60882', 'avg_buy_price_modified': False, 'unit_currency': 'KRW'}, {'currency': 'XCORE', 'balance': '0.2119', 'locked': '0', 'avg_buy_price': '0', 'avg_buy_price_modified': False, 'unit_currency': 'KRW'} ] """ if ticker_code is None: return balances else: for balance in balances: if balance['currency'] == ticker_code: return balance return None def order(self, ticker_code, side, ord_type, volume, price=None, endpoint='/v1/orders'): if ord_type=='limit': # 지정가 매수 (limit, side=bid) / 매도 (limit, side=ask) if price is None: return requestBody = dict(market='KRW-'+ticker_code, side=side, volume=volume, price=price, ord_type=ord_type) else: # 시장가 매수 (price, side=bid) / 매도 (market, side=ask) if ord_type == 'price': requestBody = dict(market='KRW-' + ticker_code, side=side, price=price, ord_type=ord_type) else: requestBody = dict(market='KRW-' + ticker_code, side=side, volume=volume, ord_type=ord_type) # Generate access token query = urlencode(requestBody).encode() hash = hashlib.sha512() hash.update(query) query_hash = hash.hexdigest() payload = { 'access_key': self.accessKey, 'nonce': str(uuid.uuid4()), 'timestamp': round(time.time() * 1000), 'query_hash': query_hash, 'query_hash_alg': 'SHA512', } jwt_token = jwt.encode(payload, self.secretKey) authorization_token = 'Bearer {}'.format(jwt_token) headers = { 'Authorization': authorization_token, 'Content-Type': 'application/json' } response = requests.post(self.apiUrl + endpoint, data=json.dumps(requestBody), headers=headers) # handle to success or fail #print(response.json()) if response.status_code == 200: return True return False # 시장가 매수한다. 2초 뒤 잔고 데이터 리스트 리턴 def buyCoinMarket(self, ticker_code, price, count=None): if price > 5000: if price < 50000: self.order(ticker_code, side='bid', ord_type='price', volume=count, price=price) buy_price = price else: repeat = 10 buy_price = int(price / 1000) * 1000 buy_amount = int(buy_price / repeat) while repeat > 0: self.order(ticker_code, side='bid', ord_type='price', volume=count, price=buy_amount) repeat -= 1 time.sleep(0.5) else: buy_price = 0 return buy_price # 시장가 매도한다. 2초 뒤 잔고 데이터 리스트 리턴 def sellCoinMarket(self, ticker_code, price, count): return self.order(ticker_code, side='ask', ord_type='market', volume=count, price=price) # 지정가 매수한다. 2초 뒤 잔고 데이터 리스트 리턴 def buyCoinLimit(self, ticker_code, price, count): return self.order(ticker_code, side='bid', ord_type='limit', volume=count, price=price) # 지정가 매도한다. 2초 뒤 잔고 데이터 리스트 리턴 def sellCoinLimit(self, ticker_code, price, count): return self.order(ticker_code, side='ask', ord_type='limit', volume=count, price=price) def getOrderBook(self, ticker_code, endpoint='/v1/orderbook'): """ 필드 설명 타입 market 마켓 코드 String timestamp 호가 생성 시각 Long total_ask_size 호가 매도 총 잔량 Double total_bid_size 호가 매수 총 잔량 Double orderbook_units 호가 List of Objects > ask_price 매도호가 Double > bid_price 매수호가 Double > ask_size 매도 잔량 Double > bid_size 매수 잔량 Double """ headers = {"accept": "application/json"} url = (self.apiUrl + endpoint + "?markets=KRW-{}").format(ticker_code) response = requests.get(url, headers=headers) # 매도 총 잔량: sum([units['ask_size'] for units in orders[0]['orderbook_units']]) # 매수 총 잔량: sum([units['bid_size'] for units in orders[0]['orderbook_units']]) orders = response.json() return orders