Дописываю бота для торговли криптой по курсу "Udemy Cryptocurrency Trading Bot with a User Interface in Python"
Бот берет определенные данные с www.testnet.binancefuture.com> информация, которую я получаю: historical candles, contracts, balances, place, cancel and order status. The Callback методы: on_open, on_error, on_close, on_message + сhannel subscription. Вот код и ошибка
class BinanceFuturesClient:
Вот какую ошибку выдает при запуске:
Бот берет определенные данные с www.testnet.binancefuture.com> информация, которую я получаю: historical candles, contracts, balances, place, cancel and order status. The Callback методы: on_open, on_error, on_close, on_message + сhannel subscription. Вот код и ошибка
class BinanceFuturesClient:
Python:
def __init__(self, public_key: str, secret_key: str, testnet: bool):
if testnet:
self._base_url = "https://testnet.binancefuture.com"
self._wss_url = "wss://stream.binancefuture.com/ws"
else:
self._base_url = "https://fapi.binance.com"
self._wss_url = "wss://fstream.binance.com/ws"
self._public_key = public_key
self._secret_key = secret_key
self._headers = {'X-MBX-APIKEY': self._public_key}
self.contracts = self.get_contracts()
self.balances = self.get_balances()
self.prices = dict()
self.strategies: typing.Dict[int, typing.Union[TechnicalStrategy, BreakoutStrategy]] = dict()
self.logs = []
self._ws_id = 1
self._ws = None
t = threading.Thread(target=self._start_ws)
t.start()
logger.info("Binance Futures Client successfully initialized")
def _add_log(self, msg: str):
logger.info("%s", msg)
self.logs.append({"log": msg, "displayed": False})
def _generate_signature(self, data: typing.Dict) -> str:
return hmac.new(self._secret_key.encode(), urlencode(data).encode(), hashlib.sha256).hexdigest()
def _make_request(self, method: str, endpoint: str, data: typing.Dict):
if method == "GET":
try:
response = requests.get(self._base_url + endpoint, params=data, headers=self._headers)
except Exception as e:
logger.error("Connection error while making %s request to %s: %s", method, endpoint, e)
return None
elif method == "POST":
try:
response = requests.post(self._base_url + endpoint, params=data, headers=self._headers)
except Exception as e:
logger.error("Connection error while making %s request to %s: %s", method, endpoint, e)
return None
elif method == "DELETE":
try:
response = requests.delete(self._base_url + endpoint, params=data, headers=self._headers)
except Exception as e:
logger.error("Connection error while making %s request to %s: %s", method, endpoint, e)
return None
else:
raise ValueError()
if response.status_code == 200:
return response.json()
else:
logger.error("Error while making %s request to %s: %s (error code %s)",
method, endpoint, response.json(), response.status_code)
return None
def get_contracts(self) -> typing.Dict[str, Contract]:
exchange_info = self._make_request("GET", "/fapi/v1/exchangeInfo", dict())
contracts = dict()
if exchange_info is not None:
for contract_data in exchange_info['symbols']:
if contract_data['marginAsset'] != "BUSD":
contracts[contract_data['symbol']] = Contract(contract_data, "binance")
return contracts
def get_historical_candles(self, contract: Contract, interval: str) -> typing.List[Candle]:
data = dict()
data['symbol'] = contract.symbol
data['interval'] = interval
data['limit'] = 1000
raw_candles = self._make_request("GET", "/fapi/v1/klines", data)
candles = []
if raw_candles is not None:
for c in raw_candles:
candles.append(Candle(c, interval, "binance"))
return candles
def get_bid_ask(self, contract: Contract) -> typing.Dict[str, float]:
data = dict()
data['symbol'] = contract.symbol
ob_data = self._make_request("GET", "/fapi/v1/ticker/bookTicker", data)
if ob_data is not None:
if contract.symbol not in self.prices:
self.prices[contract.symbol] = {'bid': float(ob_data['bidPrice']), 'ask': float(ob_data['askPrice'])}
else:
self.prices[contract.symbol]['bid'] = float(ob_data['bidPrice'])
self.prices[contract.symbol]['ask'] = float(ob_data['askPrice'])
return self.prices[contract.symbol]
def get_balances(self) -> typing.Dict[str, Balance]:
data = dict()
data['timestamp'] = int(time.time() * 1000)
data['signature'] = self._generate_signature(data)
balances = dict()
account_data = self._make_request("GET", "/fapi/v1/account", data)
if account_data is not None:
for a in account_data['assets']:
balances[a['asset']] = Balance(a, "binance")
return balances
def place_order(self, contract: Contract, order_type: str, quantity: float, side: str, price=None, tif=None) -> OrderStatus:
data = dict()
data['symbol'] = contract.symbol
data['side'] = side.upper()
data['quantity'] = round(round(quantity / contract.lot_size) * contract.lot_size, 8)
data['type'] = order_type
if price is not None:
data['price'] = round(round(price / contract.tick_size) * contract.tick_size, 8)
if tif is not None:
data['timeInForce'] = tif
data['timestamp'] = int(time.time() * 1000)
data['signature'] = self._generate_signature(data)
order_status = self._make_request("POST", "/fapi/v1/order", data)
if order_status is not None:
order_status = OrderStatus(order_status, "binance")
return order_status
def cancel_order(self, contract: Contract, order_id: int) -> OrderStatus:
data = dict()
data['orderId'] = order_id
data['symbol'] = contract.symbol
data['timestamp'] = int(time.time() * 1000)
data['signature'] = self._generate_signature(data)
order_status = self._make_request("DELETE", "/fapi/v1/order", data)
if order_status is not None:
order_status = OrderStatus(order_status, "binance")
return order_status
def get_order_status(self, contract: Contract, order_id: int) -> OrderStatus:
data = dict()
data['timestamp'] = int(time.time() * 1000)
data['symbol'] = contract.symbol
data['orderId'] = order_id
data['signature'] = self._generate_signature(data)
order_status = self._make_request("GET", "/fapi/v1/order", data)
if order_status is not None:
order_status = OrderStatus(order_status, "binance")
return order_status
def _start_ws(self):
self._ws = websocket.WebSocketApp(self._wss_url, on_open=self._on_open, on_close=self._on_close,
on_error=self._on_error, on_message=self._on_message)
while True:
try:
self._ws.run_forever()
except Exception as e:
logger.error("Binance error in run_forever() method: %s", e)
time.sleep(2)
def _on_open(self, ws):
logger.info("Binance connection opened")
self.subscribe_channel(list(self.contracts.values()), "bookTicker")
self.subscribe_channel(list(self.contracts.values()), "aggTrade")
def _on_close(self, ws):
logger.warning("Binance Websocket connection closed")
def _on_error(self, ws, msg: str):
logger.error("Binance connection error: %s", msg)
def _on_message(self, ws, msg: str):
data = json.loads(msg)
if "e" in data:
if data['e'] == "bookTicker":
symbol = data['s']
if symbol not in self.prices:
self.prices[symbol] = {'bid': float(data['b']), 'ask': float(data['a'])}
else:
self.prices[symbol]['bid'] = float(data['b'])
self.prices[symbol]['ask'] = float(data['a'])
Вот какую ошибку выдает при запуске:
Хз, не возьму в толк, что от меня требуется, буду счастлив если укажете где завтык. Заранее спасибо!error from callback <bound method BinanceFuturesClient._on_close of <connectors.binance_futures.BinanceFuturesClient object at 0x000002B05C6B57C0>>: _on_close() takes 2 positional arguments but 4 were given