Reputation: 433
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
Reputation: 2309
'ONE_DAY' is not a valid value for `granularity'.
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