apt45
apt45

Reputation: 433

"granularity argument is invalid " error with Coinbase API

I am writing my own Python script to use the Advanced Trade API of Coinbase.

I am trying to use the /api/v3/brokerage/products/{product_id}/candles endpoint to fetch historical data. Authentication works, but I get the following error when I try to get historical data

{"error":"INVALID_ARGUMENT","error_details":"granularity argument is invalid ","message":"granularity argument is invalid "}

The base code of my custom client is the following

import hmac, hashlib, requests
import time
import urllib.parse
from requests.auth import AuthBase
import datetime

class CoinbaseAuth(AuthBase):
    def __init__(self, api_key, api_secret):
        self.api_key = api_key
        self.api_secret = api_secret
    
    def __call__(self, request):
        timestamp = str(int(time.time()))
        message = timestamp + request.method + request.path_url + (request.body or b'').decode()
        
        signature = hmac.new(self.api_secret.encode('utf-8'),
                             message.encode('utf-8'),
                             digestmod=hashlib.sha256).digest().hex()
        
        request.headers.update({
            'CB-ACCESS-SIGN': signature,
            'CB-ACCESS-TIMESTAMP': timestamp,
            'CB-ACCESS-KEY': self.api_key,
            'Content-Type': 'application/json'
        })
        return request

class CoinbaseClient:
    def __init__(self, auth: CoinbaseAuth):
        self.auth = auth
    
    def request(self, http_method: str, endpoint: str, body: dict = None):
        if body is None:
            body = {}
        url = urllib.parse.urljoin('https://api.coinbase.com/', endpoint)
        response = requests.request(http_method, url, json=body, auth=self.auth)
        return response

that I can use running the following lines


config = {'api_key': 'YOUR_API_KEY',
          'api_secret': 'YOUR_SECRET_API'}

auth = CoinbaseAuth(api_key=config['api_key'], api_secret=config['api_secret'])
client = CoinbaseClient(auth=auth)


start = str(int(datetime.datetime(2023, 1, 1).timestamp()))
end = str(int(datetime.datetime(2023, 1, 3).timestamp()))

response = client.request(http_method='GET', endpoint='/api/v3/brokerage/products/BTC-USD/candles',
                          body={"start": start, "end": end, 'granularity': 'ONE_DAY'})
print(response.text)

These lines return the error {"error":"INVALID_ARGUMENT","error_details":"granularity argument is invalid ","message":"granularity argument is invalid "}

Curiously, if I make the same request but without specifying a body request, I get the data I was looking for. But this is not what the documentation of Coinbase says.

To run a test, I define a dummy_request method of the CoinbaseClient class

import hmac, hashlib, requests
import time
import urllib.parse
from requests.auth import AuthBase
import datetime

class CoinbaseAuth(AuthBase):
    def __init__(self, api_key, api_secret):
        self.api_key = api_key
        self.api_secret = api_secret
    
    def __call__(self, request):
        timestamp = str(int(time.time()))
        message = timestamp + request.method + request.path_url + (request.body or b'').decode()
        
        signature = hmac.new(self.api_secret.encode('utf-8'),
                             message.encode('utf-8'),
                             digestmod=hashlib.sha256).digest().hex()
        
        request.headers.update({
            'CB-ACCESS-SIGN': signature,
            'CB-ACCESS-TIMESTAMP': timestamp,
            'CB-ACCESS-KEY': self.api_key,
            'Content-Type': 'application/json'
        })
        return request
    
    def return_headers(self, path_url, body=''):
        timestamp = str(int(time.time()))
        message = timestamp + 'GET' + path_url + body
        signature = hmac.new(self.api_secret.encode('utf-8'),
                            message.encode('utf-8'),
                            digestmod=hashlib.sha256).digest().hex()
        return {
            'CB-ACCESS-SIGN': signature,
            'CB-ACCESS-TIMESTAMP': timestamp,
            'CB-ACCESS-KEY': self.api_key,
            'Content-Type': 'application/json'
        }

class CoinbaseClient:
    def __init__(self, auth: CoinbaseAuth):
        self.auth = auth
    
    def request(self, http_method: str, endpoint: str, body: dict = None):
        if body is None:
            body = {}
        url = urllib.parse.urljoin('https://api.coinbase.com/', endpoint)
        response = requests.request(http_method, url, json=body, auth=self.auth)
        return response
    
    def dummy_request(self):
        url = 'https://api.coinbase.com/api/v3/brokerage/products/BTC-USDC/candles?start=1672527600&end=1672614000&granularity=ONE_DAY'
        headers = self.auth.return_headers('/api/v3/brokerage/products/BTC-USDC/candles')
        response = requests.get(url, headers=headers)
        return response

By calling this new method, I get the data I was looking for. Running the following lines

response = client.dummy_request()
print(response.text)

returns {"candles":[{"start":"1672531200", "low":"16490", "high":"16621", "open":"16531.83", "close":"16611.58", "volume":"10668.73697739"}]}

Why am I getting the "INVALID_ARGUMENT" error when I specify the body request? Anyone has an idea of what is going on? Is there an error in my code?

Upvotes: 0

Views: 561

Answers (1)

nigh_anxiety
nigh_anxiety

Reputation: 2309

'ONE_DAY' is not a valid value for `granularity'.

The documentation says

The granularity field must be one of the following values: {60, 300, 900, 3600, 21600, 86400}. Otherwise, your request will be rejected. These values correspond to timeslices representing one minute, five minutes, fifteen minutes, one hour, six hours, and one day, respectively.

Upvotes: 0

Related Questions