ewizard
ewizard

Reputation: 2862

Bittrex v3 API - INVALID SIGNATURE response

I am trying to use the Bittrex v3 beta API and I keep getting:

{'code': 'INVALID_SIGNATURE'}

as a response.

I have tried it with Javascript and Python, so I am including both scripts - please let me know if you see anything wrong.

Python (first attempt):

#!/Users/eamonwhite/.pyenv/versions/3.6.3/bin/python3.6
import requests
import time
import hashlib
from pprint import pprint
import json
import hmac
import base64
import codecs

# api-endpoint 
url = "https://api.bittrex.com/v3/orders/closed"

api_key = b'yyyyyyyyy'
secret = b'xxxxxxxxx'

api_timestamp = str(int(time.time() * 1000))
print(api_timestamp)

params = {'marketSymbol':'BTC-LOOM','pageSize': 200,'startDate': '2019-09-25T01:10:27.000','endDate': '2019-09-25T01:29:27.000'}

signature = hashlib.sha512(b'').hexdigest()

pre_sign = api_timestamp+url+'GET'+signature
print(pre_sign)

pre_sign_var = pre_sign.encode()
sig = hmac.new(secret, pre_sign_var, hashlib.sha512).hexdigest()
headers = {'Api-Key': api_key, 'Api-Timestamp': api_timestamp, 'Api-Content-Hash': signature, 'Api-Signature': sig}
# sending get request and saving the response as response object 
r = requests.get(url = url, params = params, headers = headers) 

# extracting data in json format 
data = r.json() 

pprint(data)

Javascript (second attempt - pulling straight from API docs):

var CryptoJS = require("crypto-js");
const fetch = require('node-fetch');

const url = 'https://api.bittrex.com/v3/orders/closed';
const data = {'marketSymbol':'BTC-LOOM','pageSize': 200,'startDate': '2019-09-25T01:10:27.000','endDate': '2019-09-25T01:29:27.000'};

var content_hash = CryptoJS.SHA512('').toString(CryptoJS.enc.Hex);

var api_timestamp = new Date().getTime();

var pre_sign_string = api_timestamp+url+'GET'+content_hash;
var signature = CryptoJS.HmacSHA512(pre_sign_string, 'xxxxxxsecretxxxxx').toString(CryptoJS.enc.Hex);

const headers = {'Api-Key': 'zzzzz', 'Api-Timestamp': api_timestamp, 'Api-Content-Hash': content_hash, 'Api-Signature': signature, 'Content-Type': 'application/json'};

function obj_to_query(obj, base_url) {
    var parts = [];
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            parts.push(encodeURIComponent(key) + '=' + encodeURIComponent(obj[key]));
        }
    }
    return base_url+"?" + parts.join('&');
}

async function getOrders(url = '', data = {}, headers = {}) {

  return fetch(url, {
          method: 'get',
          headers: headers,
      })
      .then(res => res.json())
      .then(json => {
        console.log(json)
        return json
      });
}

var query_string = obj_to_query(data, url)

var r = getOrders(query_string, data, headers);

console.log(r);

The error I am getting back concerns the Api-Signature header, all of the other headers are correct or they would have thrown an error - I have output the string that I have before I sign it, and it looks exactly the same as in the documentation, so I feel like this must be a problem with the API because it is still in beta.

Please let me know if this is the case so I stop trying :) Thanks

Upvotes: 2

Views: 1670

Answers (2)

Ali IT
Ali IT

Reputation: 51

Thanks for sharing your python code. I made some changes and got it working sharing my code hope it helps someone else:

import requests
import time
import hashlib
from pprint import pprint
import json
import hmac
import base64
import codecs
import urllib.parse
from collections import Counter


def query(method, request, query):
   if query != '' and method == 'GET':
      url = "https://api.bittrex.com/v3/" + str(request) + str('?') + str(urllib.parse.urlencode(query))
   elif method == "DELETE":
      url = "https://api.bittrex.com/v3/" + str(request) + str('/') + str(query)
   else:
      url = "https://api.bittrex.com/v3/" + str(request)

   api_key = 'key'
   secret = 'secret'
   api_timestamp = str(int(time.time() * 1000))

   if method == "POST":
      payload = json.dumps(query)
   else:
      payload = ''

   contentHash = hashlib.sha512(payload.encode()).hexdigest()
   pre_sign = api_timestamp+url+method+contentHash
   signature = hmac.new(secret.encode(), pre_sign.encode(), hashlib.sha512).hexdigest()
   headers = {'Api-Key': api_key, 'Api-Timestamp': api_timestamp, 'Api-Content-Hash': contentHash, 'Api-Signature': signature, 'Content-Type': 'application/json', 'Accept': 'application/json'}

   if method == "POST":
      r = requests.post(url = url, data=json.dumps(query), headers = headers)
   elif method == "DELETE":
      r = requests.delete(url = url, headers = headers)
   else:
      r = requests.get(url = url, params = payload, headers = headers)

   data = r.json()
   return data

def getbalance():
    return query('GET', 'balances', '')

def getopenorders(market):
    return query('GET', 'orders/open', {'marketSymbol': market})

def buylimit(market, quantity, rate):
    return query('POST', 'orders', {'marketSymbol': market, 'direction': 'BUY', 'type': 'LIMIT', 'timeInForce': 'GOOD_TIL_CANCELLED', 'quantity': quantity, 'limit': rate})

def selllimit(market, quantity, rate):
    return query('POST', 'orders', {'marketSymbol': market, 'direction': 'SELL', 'type': 'LIMIT', 'timeInForce': 'GOOD_TIL_CANCELLED', 'quantity': quantity, 'limit': rate})

def getorderhistory(market):
    return query('GET', 'orders/closed', {'marketSymbol': market})

def cancel(uuid):
    return query('DELETE', 'orders', uuid)

#print (getbalance())
#print (getopenorders('XRP-USD'))
#print (buylimit('XRP-USD', '60', '0.10000000'))
#print (selllimit('XRP-USD', '100', '0.20000000'))
#print (getorderhistory('XRP-USD'))
#print (cancel('orderid-bla-bla-bla'))

Upvotes: 5

ewizard
ewizard

Reputation: 2862

finally got it working not sure why but one thing i did was move my url out of the variable and included it in the return statement of the function that creates the encodedURI string..however, it always spits back the same data no matter what marketSymbol I use, and only a few trades come back...this is the output i get for /orders/closed everytime regardless of marketSymbol:

[ { id: '62b7764c-2c35-4588-b01b-15fbc2e6fc16',
    marketSymbol: 'BTC-USD',
    direction: 'SELL',
    type: 'LIMIT',
    quantity: '0.00733630',
    limit: '8315.81600000',
    timeInForce: 'GOOD_TIL_CANCELLED',
    fillQuantity: '0.00733630',
    commission: '0.15251830',
    proceeds: '61.00732139',
    status: 'CLOSED',
    createdAt: '2019-09-25T16:03:53.09Z',
    updatedAt: '2019-09-25T16:03:53.09Z',
    closedAt: '2019-09-25T16:03:53.09Z' },
  { id: '21ca06f8-8e00-4d71-993c-3a7d53f57f1c',
    marketSymbol: 'BTC-USD',
    direction: 'BUY',
    type: 'LIMIT',
    quantity: '0.00733630',
    limit: '8334.93200000',
    timeInForce: 'GOOD_TIL_CANCELLED',
    fillQuantity: '0.00733630',
    commission: '0.15286890',
    proceeds: '61.14756163',
    status: 'CLOSED',
    createdAt: '2019-09-25T15:56:55.57Z',
    updatedAt: '2019-09-25T15:57:02.92Z',
    closedAt: '2019-09-25T15:57:02.92Z' },
  { id: '59f2d104-1213-4634-bbd9-6dc8e7d6b91f',
    marketSymbol: 'BTC-USD',
    direction: 'SELL',
    type: 'LIMIT',
    quantity: '0.00744902',
    limit: '8250.00000000',
    timeInForce: 'GOOD_TIL_CANCELLED',
    fillQuantity: '0.00744902',
    commission: '0.15363603',
    proceeds: '61.45441500',
    status: 'CLOSED',
    createdAt: '2019-09-24T19:43:20.76Z',
    updatedAt: '2019-09-24T19:43:21.09Z',
    closedAt: '2019-09-24T19:43:21.09Z' },
  { id: 'e39d4a85-c144-493b-98e1-99c91db5bdad',
    marketSymbol: 'BTC-USDT',
    direction: 'BUY',
    type: 'LIMIT',
    quantity: '0.00939489',
    limit: '10001.59789805',
    timeInForce: 'GOOD_TIL_CANCELLED',
    fillQuantity: '0.00939489',
    commission: '0.23468751',
    proceeds: '93.87500532',
    status: 'CLOSED',
    createdAt: '2019-09-22T16:37:46.92Z',
    updatedAt: '2019-09-22T16:37:46.92Z',
    closedAt: '2019-09-22T16:37:46.92Z' },
  { id: '5dcc5a06-1eab-460f-b353-78263e9dac0b',
    marketSymbol: 'BTC-USDT',
    direction: 'SELL',
    type: 'LIMIT',
    quantity: '0.00953213',
    limit: '9907.07077638',
    timeInForce: 'GOOD_TIL_CANCELLED',
    fillQuantity: '0.00953213',
    commission: '0.23608870',
    proceeds: '94.43548654',
    status: 'CLOSED',
    createdAt: '2019-09-22T03:21:51.15Z',
    updatedAt: '2019-09-22T03:29:40.98Z',
    closedAt: '2019-09-22T03:29:40.98Z' },
  { id: 'bdc95671-fee0-46fb-bb48-4fdf2cee7cae',
    marketSymbol: 'GRS-BTC',
    direction: 'SELL',
    type: 'LIMIT',
    quantity: '22.56987578',
    limit: '0.00002226',
    timeInForce: 'GOOD_TIL_CANCELLED',
    fillQuantity: '22.56987578',
    commission: '0.00000125',
    proceeds: '0.00050263',
    status: 'CLOSED',
    createdAt: '2019-09-22T03:15:19.59Z',
    updatedAt: '2019-09-22T03:15:19.59Z',
    closedAt: '2019-09-22T03:15:19.59Z' },
  { id: '3528c223-d40d-41bc-866c-6c92f0a38195',
    marketSymbol: 'GRS-BTC',
    direction: 'BUY',
    type: 'LIMIT',
    quantity: '22.56987578',
    limit: '0.00002254',
    timeInForce: 'GOOD_TIL_CANCELLED',
    fillQuantity: '22.56987578',
    commission: '0.00000126',
    proceeds: '0.00050871',
    status: 'CLOSED',
    createdAt: '2019-09-22T02:55:56.84Z',
    updatedAt: '2019-09-22T03:07:04.18Z',
    closedAt: '2019-09-22T03:07:04.18Z' } ]

I am submitting a ticket with Bittrex

Upvotes: 0

Related Questions