첫 번째 커밋

This commit is contained in:
javamon
2025-12-06 22:31:19 +09:00
commit 849a100fa9
33 changed files with 6613 additions and 0 deletions

628
lib/pybinancefutures.py Normal file
View File

@@ -0,0 +1,628 @@
from sys import stdout
import time
import pandas as pd
import websocket
import requests
import urllib
import json
import hmac
import hashlib
import threading
'''
That library have got just a part of Documentation
If you want to know what does certain function use can find more on
! ! !
https://binance-docs.github.io/apidocs/futures/en
! ! !
'''
class MarketData:
def __init__(self,
testnet: bool = False,
symbol: str = 'btcusdt',
interval: str = '1m'):
'''
To use TESTNET Binance Futures API -> testnet = True
To change currency pair -> symbol = 'ethusdt'
To change interval -> interval = '5m'
(m -> minutes
h -> hours
d -> days
w -> weeks
M -> months;
Valid values: [1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, 1M])
'''
if testnet == True:
self.http_way = 'http://testnet.binancefuture.com/fapi/v1/'
else:
self.http_way = 'http://fapi.binance.com/fapi/v1/'
self.wss_way = 'wss://fstream.binance.com/ws/'
self.interval = interval
self.symbol = symbol.lower()
def ping(self):
return requests.get(f'{self.http_way}ping').json()
def server_time(self):
return requests.get(f'{self.http_way}time').json()
def exchange_info(self):
return requests.get(f'{self.http_way}exchangeInfo').json()
def order_book(self, limit: int = 100):
'''
To change limit -> limit = 1000
(Valid limits:[5, 10, 20, 50, 100, 500, 1000])
'''
return requests.get(f'{self.http_way}depth?limit={limit}').json()
def recent_trades(self, limit: int = 500):
'''
To change limit -> limit = 1000
(max 1000)
'''
return requests.get(f'{self.http_way}trades?symbol={self.symbol}&limit={limit}').json()
def historical_trades(self, limit: int = 500):
'''
To change limit -> limit = 1000
(max 1000)
'''
return requests.get(f'{self.http_way}historicalTrades?symbol={self.symbol}&limit={limit}').json()
def aggregate_trades(self,
fromId: int = None,
startTime: int = None,
endTime: int = None,
limit: int = 500):
'''
To change limit -> limit = 1000
(max 1000)
To use fromId -> fromId = 1231
To use start time and end time -> startTime = 1573661424937
-> endTime = 1573661428706
'''
return requests.get(
f'{self.http_way}aggTrades?symbol={self.symbol}&fromId={fromId}&startTime={startTime}&endTime={endTime}&limit={limit}').json()
def candles_data(self,
interval: str = '1m',
startTime: int = None,
endTime: int = None,
limit: int = 500):
'''
To change interval -> interval = '5m'
(Valid values: [1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, 1M])
To use limit -> limit = 1231
(Default 500; max 1500)
To use start time and end time -> startTime = 1573661424937
-> endTime = 1573661428706
'''
return requests.get(
f'{self.http_way}klines?symbol={self.symbol}&interval={interval}&startTime={startTime}&endTime={endTime}&limit={limit}').json()
def mark_price(self):
return requests.get(f'{self.http_way}premiumIndex?symbol={self.symbol}').json()
def funding_rate(self,
startTime: int = None,
endTime: int = None,
limit: int = 100):
'''
To change limit -> limit = 1000
(max 1096)
To use start time and end time -> startTime = 1573661424937
-> endTime = 1573661428706
'''
return requests.get(
f'{self.http_way}klines?symbol={self.symbol}&startTime={startTime}&endTime={endTime}&limit={limit}').json()
def ticker_price_24h(self,
symbol: bool = False):
if symbol is True:
return requests.get(f'{self.http_way}ticker/24hr?symbol={self.symbol}').json()
else:
return requests.get(f'{self.http_way}ticker/24hr').json()
def ticker_price_symbol(self,
symbol: bool = False):
if symbol is True:
return requests.get(f'{self.http_way}ticker/price?symbol={self.symbol}').json()
else:
return requests.get(f'{self.http_way}ticker/price').json()
def ticker_orderbook_symbol(self,
symbol: bool = False):
if symbol is True:
return requests.get(f'{self.http_way}ticker/bookTicker?symbol={self.symbol}').json()
else:
return requests.get(f'{self.http_way}ticker/bookTicker').json()
def load_last_candles(self, days=30):
limit = 1440
one_hour_in_milliseconds = 3600000
one_day_in_milliseconds = one_hour_in_milliseconds * 24
startTime = int(round(time.time() * 1000)) - (one_day_in_milliseconds * 30)
data = []
for k in range(days):
r = requests.get(
f"{self.http_way}klines?symbol={self.symbol}&interval={self.interval}&limit={limit}&starttime={startTime}")
startTime += one_day_in_milliseconds
response = r.json()
for i in range(len(response)):
data.append(response[i])
stdout.write(f'\r{k + 1} of {days}')
stdout.flush()
print('\n')
'''
last_req = requests.get(f"{self.http_way}klines?symbol={self.symbol}&interval={self.interval}&limit=1")
last_res = last_req.json()
last_res = last_res[0]
if last_res[0] != data[-1][0]:
print("New candle added!")
data.append(last_res)
del data[0]
'''
df = pd.DataFrame(data)
df = df.iloc[:, :6]
df.columns = (['Date', 'Open', 'High', 'Low', 'Close', 'Volume'])
df['Date'] = pd.to_datetime(df['Date'], unit='ms')
df['Date'] = df['Date'].map(lambda x: x.strftime("%Y-%m-%d %H:%M"))
df = df.astype({'Open': 'float64',
'High': 'float64',
'Low': 'float64',
'Close': 'float64',
'Volume': 'float64'})
return df
# %%
class WebsocketMarket:
def __init__(self,
on_message=lambda ws, message: (stdout.write(f'\r{json.loads(message)}'), stdout.flush()),
on_error=lambda ws, error: print(error),
on_close=lambda ws: print("### closed ###"),
testnet: bool = False,
symbol: str = 'btcusdt',
speed: str = '100ms'):
'''
To use TESTNET Binance Futures API -> testnet = True
To change currency pair -> symbol = 'ethusdt'
To change speed -> speed = '250ms'
'''
if testnet == True:
self.wss_way = 'wss://stream.binancefuture.com/ws/'
else:
self.wss_way = 'wss://fstream.binance.com/ws/'
self.interval = '1m'
self.symbol = symbol.lower()
self.speed = speed
self.on_message = on_message
self.on_error = on_error
self.on_close = on_close
@staticmethod
def parced(func):
def parced_func(ws, msg):
return func(ws, json.loads(msg))
return parced_func
def open_socket(self, way):
thread = threading.Thread(target=lambda: self._open_socket(way))
thread.start()
def _open_socket(self, way):
websocket.enableTrace(False)
on_message_with_parce = WebsocketMarket.parced(self.on_message)
self.ws = websocket.WebSocketApp(way,
on_message=on_message_with_parce,
on_close=self.on_close,
on_error=self.on_error)
self.ws.run_forever()
def aggregate_trade_socket(self):
self.open_socket(f'{self.wss_way}{self.symbol}@aggTrade')
def mark_price_socket(self):
self.open_socket(f'{self.wss_way}{self.symbol}@markPrice')
def candle_socket(self):
self.open_socket(f'{self.wss_way}{self.symbol}@kline_{self.interval}')
def individual_symbol_mini_ticker(self):
self.open_socket(f'{self.wss_way}{self.symbol}@miniTicker')
def individual_symbol_ticker(self):
self.open_socket(f'{self.wss_way}{self.symbol}@ticker')
def all_book_ticker(self):
self.open_socket(f'{self.wss_way}!bookTicker')
def partial_book_depth_socket(self,
levels: int = 20):
'''
To change count of top bids and asks -> levels = 5
(5, 10 or 20 values are valid)
'''
self.open_socket(f'{self.wss_way}{self.symbol}@depth{levels}@{self.speed}')
def diff_book_depth_socket(self):
self.open_socket(f'{self.wss_way}{self.symbol}@depth@{self.speed}')
# %%
class Client:
def __init__(self,
api_key: str,
sec_key: str,
testnet: bool = False,
symbol: str = 'BTCUSDT'):
'''
In any case you must give your API key and API secret to work with Client
To use TESTNET Binance Futures API -> testnet = True
To change currency pair -> symbol = 'ethusdt'
'''
self.api_key = api_key
self.sec_key = sec_key
self.http_way = 'http://fapi.binance.com/fapi/v1/'
self.symbol = symbol
self.X_MBX_APIKEY = {"X-MBX-APIKEY": self.api_key}
if testnet == True:
self.http_way = 'http://testnet.binancefuture.com/fapi/v1/'
self.wss_way = 'wss://stream.binancefuture.com/ws/'
else:
self.http_way = 'http://fapi.binance.com/fapi/v1/'
self.wss_way = 'wss://fstream.binance.com/ws/'
def open_socket(self, way, on_message, on_error, on_close):
websocket.enableTrace(False)
self.ws = websocket.WebSocketApp(way,
on_message=on_message,
on_error=on_error,
on_close=on_close)
self.ws.run_forever()
def _get_request(self,
req,
query):
r = requests.get(self.request_url(req=req,
query=query,
signature=self.get_sign(query=query)),
headers=self.X_MBX_APIKEY)
try:
return r.json()
except:
if str(r) == '<Response [200]>':
return dict([])
else:
return r
def _post_request(self,
req,
query):
r = requests.post(self.request_url(req=req,
query=query,
signature=self.get_sign(query=query)),
headers=self.X_MBX_APIKEY)
try:
return r.json()
except:
if str(r) == '<Response [200]>':
return dict([])
else:
return r
def _delete_request(self,
req,
query):
r = requests.delete(self.request_url(req=req,
query=query,
signature=self.get_sign(query=query)),
headers=self.X_MBX_APIKEY)
try:
return r.json()
except:
if str(r) == '<Response [200]>':
return dict([])
else:
return r
def _put_request(self,
req,
query):
r = requests.put(self.request_url(req=req,
query=query,
signature=self.get_sign(query=query)),
headers=self.X_MBX_APIKEY)
try:
return r.json()
except:
if str(r) == '<Response [200]>':
return dict([])
else:
return r
@staticmethod
def timestamp():
return int(time.time() * 1000) - 1000
return int(time.time() * 1000)
def get_sign(self, query):
return hmac.new(self.sec_key.encode('utf-8'), query.encode('utf-8'), hashlib.sha256).hexdigest()
def request_url(self, req, query, signature):
return self.http_way + req + query + '&signature=' + signature
def new_order(self,
side: str,
orderType: str,
quantity: float,
timeInForce: float = None,
reduceOnly: bool = False,
price: float = None,
newClientOrderId: str = None,
stopPrice: float = None,
workingType: str = None):
'''
POST
Choose side: SELL or BUY
Choose quantity: 0.001
Choose price: 7500
To change order type -> orderType = 'MARKET'
To change time in force -> timeInForce = 'IOC'
'''
req = 'order?'
querystring = {'symbol': self.symbol,
'side': side,
'type': orderType,
'quantity': quantity,
'reduceOnly': reduceOnly}
if timeInForce is not None:
querystring['timeInForce'] = timeInForce
if price is not None:
querystring['price'] = price
if newClientOrderId is not None:
querystring['newClientOrderId'] = newClientOrderId
if stopPrice is not None:
querystring['stopPrice'] = stopPrice
if workingType is not None:
querystring['workingType'] = workingType
querystring['timestamp'] = self.timestamp()
querystring = urllib.parse.urlencode(querystring)
return self._post_request(req, querystring)
def query_order(self, orderId):
'''
GET
Choose orderId: 156316486
'''
req = 'order?'
querystring = urllib.parse.urlencode({'symbol': self.symbol,
'orderId': orderId,
'timestamp': self.timestamp()})
return self._get_request(req, querystring)
def cancel_order(self, orderId):
'''
DELETE
Choose orderId: 156316486
'''
req = 'order?'
querystring = urllib.parse.urlencode({'symbol': self.symbol,
'orderId': orderId,
'timestamp': self.timestamp()})
return self._delete_request(req, querystring)
def current_open_orders(self):
'''
GET
'''
req = 'openOrders?'
querystring = urllib.parse.urlencode({'timestamp': self.timestamp()})
return self._get_request(req, querystring)
def all_orders(self,
limit: int = 1000,
startTime: int = None,
endTime: int = None):
'''
GET
To change limit of output orders -> limit = 1000
(max value is 1000)
To use start time and end time -> startTime = 1573661424937
-> endTime = 1573661428706
'''
req = 'allOrders?'
querystring = urllib.parse.urlencode({'symbol': self.symbol,
'timestamp': self.timestamp(),
'limit': limit,
'startTime': startTime,
'endTime': endTime})
return self._get_request(req, querystring)
def balance(self):
'''
GET
'''
req = 'balance?'
querystring = urllib.parse.urlencode({'timestamp': self.timestamp()})
return self._get_request(req, querystring)
def account_info(self):
'''
GET
'''
req = 'account?'
querystring = urllib.parse.urlencode({'timestamp': self.timestamp()})
return self._get_request(req, querystring)
def change_leverage(self, leverage):
'''
POST
To change leverage -> leverage = 25
(from 1 to 125 are valid values)
'''
req = 'leverage?'
querystring = urllib.parse.urlencode({'symbol': self.symbol,
'leverage': leverage,
'timestamp': self.timestamp()})
return self._post_request(req, querystring)
def position_info(self):
'''GET'''
req = 'positionRisk?'
querystring = urllib.parse.urlencode({'timestamp': self.timestamp()})
return self._get_request(req, querystring)
def trade_list(self,
limit: int = 1000,
startTime: int = None,
endTime: int = None):
'''
GET
To change limit of output orders -> limit = 1000
(max value is 1000)
To use start time and end time -> startTime = 1573661424937
-> endTime = 1573661428706
'''
req = 'userTrades?'
querystring = urllib.parse.urlencode({'symbol': self.symbol,
'timestamp': self.timestamp(),
'limit': limit,
'startTime': startTime,
'endTime': endTime})
return self._get_request(req, querystring)
def income_history(self,
limit: int = 1000):
'''
GET
To change limit of output orders -> limit = 1000
(max value is 1000)
'''
req = 'income?'
querystring = urllib.parse.urlencode({'symbol': self.symbol,
'timestamp': self.timestamp(),
'limit': limit})
return self._get_request(req, querystring)
def start_stream(self):
'''
POST
'''
req = 'listenKey?'
querystring = urllib.parse.urlencode({'timestamp': self.timestamp()})
return self._post_request(req, querystring)
def get_listen_key(self):
return self.start_stream()['listenKey']
def keepalive_stream(self):
'''
PUT
'''
req = 'listenKey?'
querystring = urllib.parse.urlencode({'timestamp': self.timestamp()})
return self._put_request(req, querystring)
def close_stream(self):
'''
DELETE
'''
req = 'listenKey?'
querystring = urllib.parse.urlencode({'timestamp': self.timestamp()})
return self._delete_request(req, querystring)
def user_update_socket(self,
on_message,
on_error,
on_close):
listen_key = self.get_listen_key()
self.open_socket(f'{self.wss_way}{listen_key}', on_message, on_error, on_close)
def stop_user_update_socket(self):
self.close_stream()
def on_new_candle_loaded(ws, candle):
print(ws, candle)