Найти - Пользователи
Полная версия: В чем может быть Error from callback >>> takes 2 positional arguments but 4 were given ?
Начало » Python для новичков » В чем может быть Error from callback >>> takes 2 positional arguments but 4 were given ?
1
lieus
Дописываю бота для торговли криптой по курсу “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:

     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'])
                # PNL Calculation
                try:
                    for b_index, strat in self.strategies.items():
                        if strat.contract.symbol == symbol:
                            for trade in strat.trades:
                                if trade.status == "open" and trade.entry_price is not None:
                                    if trade.side == "long":
                                        trade.pnl = (self.prices[symbol]['bid'] - trade.entry_price) * trade.quantity
                                    elif trade.side == "short":
                                        trade.pnl = (trade.entry_price - self.prices[symbol]['ask']) * trade.quantity
                except RuntimeError as e:
                    logger.error("Error while looping through the Binance strategies: %s", e)
            if data['e'] == "aggTrade":
                symbol = data['s']
                for key, strat in self.strategies.items():
                    if strat.contract.symbol == symbol:
                        res = strat.parse_trades(float(data['p']), float(data['q']), data['T'])
                        strat.check_trade(res)
    def subscribe_channel(self, contracts: typing.List[Contract], channel: str):
        data = dict()
        data['method'] = "SUBSCRIBE"
        data['params'] = []
        for contract in contracts:
            data['params'].append(contract.symbol.lower() + "@" + channel)
        data['id'] = self._ws_id
        try:
            self._ws.send(json.dumps(data))
        except Exception as e:
            logger.error("Websocket error while subscribing to %s %s updates: %s", len(contracts), channel, e)
        self._ws_id += 1
    def get_trade_size(self, contract: Contract, price: float, balance_pct: float):
        balance = self.get_balances()
        if balance is not None:
            if 'USDT' in balance:
                balance = balance['USDT'].wallet_balance
            else:
                return None
        else:
            return None
        trade_size = (balance * balance_pct / 100) / price
        trade_size = round(round(trade_size / contract.lot_size) * contract.lot_size, 8)
        logger.info("Binance Futures current USDT balance = %s, trade size = %s", balance, trade_size)
        return trade_size
Вот какую ошибку выдает при запуске:
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

Хз, не возьму в толк, что от меня требуется, буду счастлив если укажете где завтык. Заранее спасибо!
FishHook
     def _on_close(self, ws):
        logger.warning("Binance Websocket connection closed")

     def _on_close(self, ws, *args):
        logger.warning("Additional arguments were passed {}".format(args))
        logger.warning("Binance Websocket connection closed")
maksimovgenya
Да, такая же паника, не могу понять в чем проблема, только начал копать этот код!
До этого момента все было ровно!

Вроде лимиты на подписку не превышал!

FishHook
def _on_close(self, ws, *args):
logger.warning(“Additional arguments were passed {}”.format(args))
logger.warning(“Binance Websocket connection closed”)

Выдает такой цикл:

2022-04-14 19:32:59,968 INFO :: Binance Futures Client successfully initialized
2022-04-14 19:33:00,393 INFO :: Bitmex Client successfully initialized
2022-04-14 19:33:01,045 INFO :: Bitmex connection opened
2022-04-14 19:33:01,118 INFO :: Binance connection opened

2022-04-14 19:33:01,379 WARNING :: Additional arguments were passed (3003, ‘subscribed channels exceeds limit’)
2022-04-14 19:33:01,379 WARNING :: Binance Websocket connection closed

2022-04-14 19:33:04,526 INFO :: Binance connection opened
2022-04-14 19:33:04,786 WARNING :: Additional arguments were passed (3003, ‘subscribed channels exceeds limit’)

и т.д.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB