첫 번째 커밋
This commit is contained in:
628
lib/pybinancefutures.py
Normal file
628
lib/pybinancefutures.py
Normal 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)
|
||||
Reference in New Issue
Block a user