BitMEX / api-connectors

Libraries for connecting to the BitMEX API.
https://www.bitmex.com/app/restAPI
910 stars 795 forks source link

jsonschema.exceptions.ValidationError: 'XBT' is not of type 'number' #550

Open NeutronBlast opened 4 months ago

NeutronBlast commented 4 months ago

Name: 'XBT' is not of type 'number' Description: This error is generated when I'm going to use Trade_getBucketed in order to get OHLCV data. I've been using Bitmex API for months and I never had issues with this method but it started generating errors today. This my usage:

import bitmex

class Bitmex:
    def __init__(self, api_key, api_secret):
        self.api_key = api_key
        self.api_secret = api_secret
        self.exchange_name_tv = 'BITMEX'

    @staticmethod
    def format_ohlcv(ohlcv_data):
        """
        Formats OHLCV (Open, High, Low, Close, Volume) data into a specific structure.

        Parameters:
        - ohlcv_data (list): List of dictionaries containing OHLCV data.

        Returns:
        - list: Transformed OHLCV data with specific fields (open, close, high, low, volume, time).
        """
        transformed_data = [
            {
                'open': item['open'],
                'close': item['close'],
                'high': item['high'],
                'low': item['low'],
                'volume': item['volume'],
                'time': int(item['timestamp'].timestamp() * 1000)  # Convert to milliseconds
            }
            for item in ohlcv_data
        ]

        return transformed_data

    def get_ohlc(self, ticker, timeframe):
        """
        Retrieves OHLCV (Open, High, Low, Close, Volume) data for a specific ticker and timeframe.

        Parameters:
        - ticker (str): Symbol or identifier of the financial instrument.
        - timeframe (str): Timeframe for the OHLCV data (e.g., '1h', '1d').

        Returns:
        - list: OHLCV data in a specific format after applying formatting.

        Example:
        [{'open': 100, 'close': 110, 'high': 120, 'low': 90, 'volume': 1000, 'time': 1640995200000},
         {'open': 110, 'close': 120, 'high': 130, 'low': 100, 'volume': 1500, 'time': 1641081600000}]

        """
        client = bitmex.bitmex(test=False, api_key=self.api_key, api_secret=self.api_secret)
        result = client.Trade.Trade_getBucketed(binSize=timeframe, symbol=ticker, reverse=True, count=500).result()
        result = self.format_ohlcv(result[0])
        return result

Call:

import os
import unittest

from dotenv import load_dotenv

from exchanges.bitmex.bitmex import Bitmex

class TestBitmex(unittest.TestCase):
    def setUp(self):
        # Load dotenv and create a Bitget object
        load_dotenv()

        self.bitmex = Bitmex(os.getenv('BITMEX_API_KEY'),
                             os.getenv('BITMEX_API_SECRET'))

    def test_get_ohlc(self):
        result = self.bitmex.get_ohlc('.BVOL24H', "1d")
        print(result)
        print(len(result))

if __name__ == '__main__':
    unittest.main()

Traceback of the error:

Traceback (most recent call last):
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\venv\Lib\site-packages\swagger_spec_validator\common.py", line 34, in wrapper
    return method(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\venv\Lib\site-packages\swagger_spec_validator\validator20.py", line 254, in validate_value_type
    validate_schema_value(
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\venv\Lib\site-packages\swagger_spec_validator\ref_validators.py", line 118, in validate_schema_value
    ).validate(value)
      ^^^^^^^^^^^^^^^
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\venv\Lib\site-packages\jsonschema\validators.py", line 438, in validate
    raise error
jsonschema.exceptions.ValidationError: 'XBT' is not of type 'number'

Failed validating 'type' in schema:
    {'default': 'XBT', 'format': 'double', 'type': 'number'}

On instance:
    'XBT'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\tests\test_exchanges\test_bitmex\test_bitmex.py", line 18, in test_get_ohlc
    result = self.bitmex.get_ohlc('.BVOL24H', "1d")
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\exchanges\bitmex\bitmex.py", line 52, in get_ohlc
    client = bitmex.bitmex(test=False, api_key=self.api_key, api_secret=self.api_secret)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\venv\Lib\site-packages\bitmex.py", line 35, in bitmex
    return SwaggerClient.from_url(spec_uri, config=config, http_client=request_client)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\venv\Lib\site-packages\bravado\client.py", line 109, in from_url
    return cls.from_spec(spec_dict, spec_url, http_client, config)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\venv\Lib\site-packages\bravado\client.py", line 135, in from_spec
    swagger_spec = Spec.from_dict(
                   ^^^^^^^^^^^^^^^
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\venv\Lib\site-packages\bravado_core\spec.py", line 355, in from_dict
    spec.build()
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\venv\Lib\site-packages\bravado_core\spec.py", line 367, in build
    self._validate_spec()
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\venv\Lib\site-packages\bravado_core\spec.py", line 360, in _validate_spec
    self.resolver = validator20.validate_spec(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\venv\Lib\site-packages\swagger_spec_validator\validator20.py", line 186, in validate_spec
    validate_apis(cast("dict[Any, Any]", apis), bound_deref)
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\venv\Lib\site-packages\swagger_spec_validator\validator20.py", line 430, in validate_apis
    validate_responses(api_name, oper_name, oper_body["responses"], deref)
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\venv\Lib\site-packages\swagger_spec_validator\validator20.py", line 310, in validate_responses
    validate_definition(
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\venv\Lib\site-packages\swagger_spec_validator\validator20.py", line 575, in validate_definition
    validate_arrays_in_definition(
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\venv\Lib\site-packages\swagger_spec_validator\validator20.py", line 514, in validate_arrays_in_definition
    validate_definition(
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\venv\Lib\site-packages\swagger_spec_validator\validator20.py", line 574, in validate_definition
    validate_defaults_in_definition(definition, deref)
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\venv\Lib\site-packages\swagger_spec_validator\validator20.py", line 498, in validate_defaults_in_definition
    validate_property_default(property_spec, deref)
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\venv\Lib\site-packages\swagger_spec_validator\validator20.py", line 489, in validate_property_default
    validate_value_type(
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\venv\Lib\site-packages\swagger_spec_validator\common.py", line 36, in wrapper
    raise SwaggerValidationError(str(e), e).with_traceback(sys.exc_info()[2])
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\venv\Lib\site-packages\swagger_spec_validator\common.py", line 34, in wrapper
    return method(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\venv\Lib\site-packages\swagger_spec_validator\validator20.py", line 254, in validate_value_type
    validate_schema_value(
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\venv\Lib\site-packages\swagger_spec_validator\ref_validators.py", line 118, in validate_schema_value
    ).validate(value)
      ^^^^^^^^^^^^^^^
  File "C:\Users\Hyper\OneDrive\Documents\GitHub\RTrader-Worker\venv\Lib\site-packages\jsonschema\validators.py", line 438, in validate
    raise error
swagger_spec_validator.common.SwaggerValidationError: ("'XBT' is not of type 'number'\n\nFailed validating 'type' in schema:\n    {'default': 'XBT', 'format': 'double', 'type': 'number'}\n\nOn instance:\n    'XBT'", <ValidationError: "'XBT' is not of type 'number'">)

Ran 1 test in 1.800s

FAILED (errors=1)
henry1034 commented 4 months ago

same here

andre783 commented 4 months ago

Same issue here when calling bitmex.bitmex(test=False, api_key=bitmex_api_key, api_secret=bitmex_api_secret). My trading bot has open trades and cannot reconnect.

NeutronBlast commented 4 months ago

Just to get my thing working I made the request to V1 API manually with requests library given that the only thing that I want to get is BVOL data. Unfortunately, if you're using the SDK for orders or trades this won't help, hopefully it gets resolved soon. Leaving it open.

class Bitmex:
    def __init__(self, api_key, api_secret):
        self.api_key = api_key
        self.api_secret = api_secret
        self.exchange_name_tv = 'BITMEX'

    @staticmethod
    def format_ohlcv(ohlcv_data):
        """
        Formats OHLCV (Open, High, Low, Close, Volume) data into a specific structure.

        Parameters:
        - ohlcv_data (list): List of dictionaries containing OHLCV data.

        Returns:
        - list: Transformed OHLCV data with specific fields (open, close, high, low, volume, time).
        """
        transformed_data = [
            {
                'open': item['open'],
                'close': item['close'],
                'high': item['high'],
                'low': item['low'],
                'volume': item['volume'],
                'time': int(datetime.fromisoformat(item['timestamp'].replace('Z', '+00:00')).timestamp() * 1000)
                # 'time': int(item['timestamp'].timestamp() * 1000)  # Convert to milliseconds
            }
            for item in ohlcv_data
        ]

        return transformed_data

    def get_ohlc(self, ticker, timeframe):
        """
        Retrieves OHLCV (Open, High, Low, Close, Volume) data for a specific ticker and timeframe.

        Parameters:
        - ticker (str): Symbol or identifier of the financial instrument.
        - timeframe (str): Timeframe for the OHLCV data (e.g., '1h', '1d').

        Returns:
        - list: OHLCV data in a specific format after applying formatting.

        Example:
        [{'open': 100, 'close': 110, 'high': 120, 'low': 90, 'volume': 1000, 'time': 1640995200000},
         {'open': 110, 'close': 120, 'high': 130, 'low': 100, 'volume': 1500, 'time': 1641081600000}]

        """
        path = 'api/v1/trade/bucketed'
        method = "GET"
        payload = {
            "binSize": f"{timeframe}",
            "partial": False,
            "symbol": f"{ticker}",
            "count": 100,
            "reverse": True
        }
        url = f"{os.getenv('BITMEX_API_URL')}{path}"
        try:
            response = requests.request(method, url, params=payload, timeout=10)
            response = response.json()
            return self.format_ohlcv(response)
        except (requests.exceptions.ConnectionError, requests.exceptions.JSONDecodeError) as e:
            raise ExchangeConnectionError("Failed to establish a connection to Bitmex. There is an error on their "
                                          "end") from e
        except (requests.exceptions.ReadTimeout, requests.exceptions.Timeout) as e:
            raise ExchangeRequestTimeOut("Connection with Bitmex has timed out") from e
        # client = bitmex.bitmex(test=False, api_key=self.api_key, api_secret=self.api_secret)
        # result = client.Trade.Trade_getBucketed(binSize=timeframe, symbol=ticker, reverse=True, count=500).result()
        # result = self.format_ohlcv(result[0])

Call

class TestBitmex(unittest.TestCase):
    def setUp(self):
        # Load dotenv and create a Bitmex object
        load_dotenv()

        self.bitmex = Bitmex(os.getenv('BITMEX_API_KEY'),
                             os.getenv('BITMEX_API_SECRET'))

    def test_get_ohlc(self):
        result = self.bitmex.get_ohlc('.BVOL24H', "1d")
        print(result)
        # print(len(result))

if __name__ == '__main__':
    unittest.main()
henry1034 commented 4 months ago

I have built one you can place orders to and from if useful too

andre783 commented 4 months ago

I have built one you can place orders to and from if useful too

I would find that very useful if you are able to share.

henry1034 commented 4 months ago

I have built one you can place orders to and from if useful too

I would find that very useful if you are able to share.

Try this: https://github.com/henry1034/BitMexRestApi

Don't know how well it works but it does what I need at the moment. I added in @NeutronBlast's data functions too but haven't tested them

andre783 commented 4 months ago

I have built one you can place orders to and from if useful too

I would find that very useful if you are able to share.

Try this: https://github.com/henry1034/BitMexRestApi

Don't know how well it works but it does what I need at the moment. I added in @NeutronBlast's data functions too but haven't tested them

Thanks a lot!