This commit is contained in:
dsyoon
2026-01-28 18:58:33 +09:00
commit c45ad151b6
24 changed files with 7599 additions and 0 deletions

306
HTS2.py Normal file
View File

@@ -0,0 +1,306 @@
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