I have looked through the FTX API documentation found here: https://docs.ftx.us/#overview
And I've looked at the example code found in this repo: https://github.com/ftexchange/ftx/tree/master/rest
I can't get or post anything that requires Authentication. I am using the API key on my account that has 'full trade permissions', and when I look at print(request.headers) the headers look like they are in the right format.
Let me know if you need any more information, my code returns
Error Code: 400 Invalid API Key
import time
import hmac
from requests import Request
ts = int(time.time() * 1000)
request = Request('GET', 'https://ftx/api/wallet/balances')
prepared = request.prepare()
signature_payload = f'{ts}{prepared.method}{prepared.path_url}'.encode()
signature = hmac.new('API SECRET'.encode(), signature_payload, 'sha256').hexdigest()
request.headers[f'FTXUS-KEY'] = API KEY'
request.headers[f'FTXUS-SIGN'] = signature
request.headers[f'FTXUS-TS'] = str(ts)
res = requests.get('https://ftx/api/wallet/balances', headers=prepared.headers)
r = res.json()
I also got this error and It was a silly mistake.
I think you have FTX.US API Key and you are hitting on 'https://ftx/api/wallet/balances'. U should hit on 'https://ftx.us/api/wallet/balances' to get this working
Related
I do have some tutorial code that makes use of the bit.ly API v3 for shortening an URL response. I would like to migrate this code to the v4 API but I do not understand how to set up the correct API endpoint. At least I think this is my error and the API documentation is difficult to understand and to adapt for me, as I'm a beginner.
I do have 2 files to work with:
bitlyhelper.py (this needs to be migrated to bit.ly API v4)
views.py
This is the relevant code that relates to the URL shortening.
bitlyhelper.py
import requests
#import json
TOKEN = "my_general_access_token"
ROOT_URL = "https://api-ssl.bitly.com"
SHORTEN = "/v3/shorten?access_token={}&longUrl={}"
class BitlyHelper:
def shorten_url(self, longurl):
try:
url = ROOT_URL + SHORTEN.format(TOKEN, longurl)
r = requests.get(url)
jr = r.json()
return jr['data']['url']
except Exception as e:
print (e)
views.py
from .bitlyhelper import BitlyHelper
BH = BitlyHelper()
#usr_account.route("/account/createtable", methods=["POST"])
#login_required
def account_createtable():
form = CreateTableForm(request.form)
if form.validate():
tableid = DB.add_table(form.tablenumber.data, current_user.get_id())
new_url = BH.shorten_url(config.base_url + "newrequest/" + tableid)
DB.update_table(tableid, new_url)
return redirect(url_for('account.account'))
return render_template("account.html", createtableform=form, tables=DB.get_tables(current_user.get_id()))
The code does work fine when using the v3 API.
I tried a few combinations of the API endpoint, but couldn't get it to work.
for example simply changing the version number does not work.
SHORTEN = "/v4/shorten?access_token={}&longUrl={}"
It would be great if someone could help with setting up the proper API endpoint.
Here is the API documentation: https://dev.bitly.com/v4_documentation.html
This is the relevant part I think:
import requests
header = {
"Authorization": "Bearer <TOKEN HERE>",
"Content-Type": "application/json"
}
params = {
"long_url": form.url.data
}
response = requests.post("https://api-ssl.bitly.com/v4/shorten", json=params, headers=header)
data = response.json()
if 'link' in data.keys(): short_link = data['link']
else: short_link = None
First you want to create the request header with your bearer token.
Make sure to set the content type too.
After setting your header you have to provide the url you would like to shorten for example.
The data variable contains your 201 request.
I got some help and ended up using bitlyshortener from here: https://pypi.org/project/bitlyshortener/
In this way:
from bitlyshortener import Shortener
tokens_pool = ['bitly_general_access_token'] # Use your own.
shortener = Shortener(tokens=tokens_pool, max_cache_size=128)
#usr_account.route("/account/createtable", methods=["POST"])
def account_createtable():
form = CreateTableForm(request.form)
if form.validate():
tableid = DB.add_table(form.tablenumber.data, current_user.get_id())
new_urls = [f'{config.base_url}newrequest/{tableid}']
short_url = shortener.shorten_urls(new_urls)[0]
DB.update_table(tableid, short_url)
return redirect(url_for('account.account'))
return render_template("account.html", createtableform=form, tables=DB.get_tables(current_user.get_id()))
This does work perfectly fine, and bitlyshortener even adds the s to https://my_shortlink automagically.
It makes sense that your v3 code fails against v4, based on this:
Authentication
How you authenticate to the Bitly API has changed with V4. Previously your authentication token would be provided as the access_token query parameter on each request. V4 instead requires that the token be provided as part of the Authorization header on each request.
You will want to move your token out of the args and into the header.
Using https://github.com/bitly/bitly-api-python might possibly be an option,
except that it is some years since it was last updated.
I am writing a custom Python class to encapsulate the Poloniex trading API. However, I am running in to a problem with the request returning a "404 Error". I have been over and over the documentation and am quite sure that I am utilizing the right endpoint... What else could I be doing wrong here:
...
self.trading_api = 'https://poloniex.com/tradingapi'
self.api_key = 'My API key'
self.secret_key = bytes('My Secret Key', 'latin-1')
...
req['nonce'] = int(time.time()*1000)
data = urllib.parse.urlencode(req).encode()
sign = hmac.new(self.secret_key, data, sha512)
signature=sign.hexdigest()
headers = dict(Key=self.api_key, Sign=signature)
conn = urllib.request.Request(self.trading_api, headers=headers)
self.rate_limit()
try:
requested = urllib.request.urlopen(conn, data=data)
return requested
The A in the url must be capitalized:
self.trading_api = 'https://poloniex.com/tradingApi'
While Poloniex's documentation does not make note of this (in fact the url used was copied directly from their page), remember to capitalize it!
I am learning how to use the Kucoin and am having trouble with the authenticating myself to the API server.
I am trying to load all of the active orders however keep getting a 401 error.
The Kucoin API documentation states that I need to add this:
{
"KC-API-KEY": "59c5ecfe18497f5394ded813",
"KC-API-NONCE" : 1506219855000 //Client timestamp (exact to
milliseconds), before using the calibration time, the server does not
accept calls with a time difference of more than 3 seconds
"KC-API-SIGNATURE" :
"fd83147802c361575bbe72fef32ba90dcb364d388d05cb909c1a6e832f6ca3ac"
//signature after client encryption
}
as a parameter to headers of request. I am unsure what this means. Any help will be appreciated.
Creating the header can be a little tricky.
For the nonce value, or any millisecond timestamp value, I've found the best way to generate this is like this
import time
int(time.time() * 1000)
The signature requires you to order the parameters alphabetically in a query string format, combine that with the path and nonce and then hash the string using sha256 with your secret key.
If you'd like to implement it yourself feel free to copy the code from here, it's split over a few functions and should be quite readable https://github.com/sammchardy/python-kucoin/blob/0ece729c406056a428a57853345c9931d449be02/kucoin/client.py#L117
Or alternatively you may be best off just using that library. (Note: I'm the author and maintainer of python-kucoin)
Here are my working codes in Python 3:
import requests
import json
import hmac
import hashlib
import base64
from urllib.parse import urlencode
import time
api_key = 'xxxxx'
api_secret = 'xx-xxx-xx'
api_passphrase = 'xxx' #note that this is *not* trading password
base_uri = 'https://api.kucoin.com'
def get_headers(method, endpoint):
now = int(time.time() * 1000)
str_to_sign = str(now) + method + endpoint
signature = base64.b64encode(hmac.new(api_secret.encode(), str_to_sign.encode(), hashlib.sha256).digest()).decode()
passphrase = base64.b64encode(hmac.new(api_secret.encode(), api_passphrase.encode(), hashlib.sha256).digest()).decode()
return {'KC-API-KEY': api_key,
'KC-API-KEY-VERSION': '2',
'KC-API-PASSPHRASE': passphrase,
'KC-API-SIGN': signature,
'KC-API-TIMESTAMP': str(now)
}
#List Accounts
method = 'GET'
endpoint = '/api/v1/accounts'
response = requests.request(method, base_uri+endpoint, headers=get_headers(method,endpoint))
print(response.status_code)
print(response.json())
Output
200
{'code': '200000', 'data': [{'available': blah,blah,blah }]}
I only manage to use the Emotion API subscription key for pictures but never for videos. It makes no difference whether I use the API Testing Console or try to call the Emotion API by Pathon 2.7. In both cases I get a response status 202 Accepted, however when opening the Operation-Location it says
{ "error": { "code": "Unauthorized", "message": "Access denied due to
invalid subscription key. Make sure you are subscribed to an API you are
trying to call and provide the right key." } }
On the Emotion API explanatory page it says that Response 202 means that
The service has accepted the request and will start the process later.
In the response, there is a "Operation-Location" header. Client side should further query the operation status from the URL specified in this header.
Then there is Response 401, which is exactly what my Operation-Location contains. I do not understand why I'm getting a response 202 which looks like response 401.
I have tried to call the API with Python using at least three code versions that I found on the Internet that
all amount to the same, I found the code here :
Microsoft Emotion API for Python - upload video from memory
python-upload-video-from-memory
import httplib
import urllib
import base64
import json
import pandas as pd
import numpy as np
import requests
_url = 'https://api.projectoxford.ai/emotion/v1.0/recognizeInVideo'
_key = '**********************'
_maxNumRetries = 10
paramsPost = urllib.urlencode({'outputStyle' : 'perFrame', \
'file':'C:/path/to/file/file.mp4'})
headersPost = dict()
headersPost['Ocp-Apim-Subscription-Key'] = _key
headersPost['content-type'] = 'application/octet-stream'
jsonGet = {}
headersGet = dict()
headersGet['Ocp-Apim-Subscription-Key'] = _key
paramsGet = urllib.urlencode({})
responsePost = requests.request('post', _url + "?" + paramsPost, \
data=open('C:/path/to/file/file.mp4','rb').read(), \
headers = headersPost)
print responsePost.status_code
videoIDLocation = responsePost.headers['Operation-Location']
print videoIDLocation
Note that changing _url = 'https://api.projectoxford.ai/emotion/v1.0/recognizeInVideo' to _url =
'https://westus.api.cognitive.microsoft.com/emotion/v1.0/recognizeInVideo' doesn't help.
However, afterwards I wait and run every half an hour:
getResponse = requests.request('get', videoIDLocation, json = jsonGet,\
data = None, headers = headersGet, params = paramsGet)
print json.loads(getResponse.text)['status']
The outcome has been 'Running' for hours and my video is only about half an hour long.
Here is what my Testing Console looks like Testing Console for Emotion API, Emotion Recognition in Video
Here I used another video that is about 5 minutes long and available on the internet. I found the video in a different usage example
https://benheubl.github.io/data%20analysis/fr/
that uses a very similar code, which again gets me a response status 202 Accepted and when opening the Operation-Location the subscription key is wrong
Here the code:
import httplib
import urllib
import base64
import json
import pandas as pd
import numpy as np
import requests
# you have to sign up for an API key, which has some allowances. Check the
API documentation for further details:
_url = 'https://api.projectoxford.ai/emotion/v1.0/recognizeinvideo'
_key = '*********************' #Here you have to paste your
primary key
_maxNumRetries = 10
# URL direction: I hosted this on my domain
urlVideo = 'http://datacandy.co.uk/blog2.mp4'
# Computer Vision parameters
paramsPost = { 'outputStyle' : 'perFrame'}
headersPost = dict()
headersPost['Ocp-Apim-Subscription-Key'] = _key
headersPost['Content-Type'] = 'application/json'
jsonPost = { 'url': urlVideo }
responsePost = requests.request( 'post', _url, json = jsonPost, data = None,
headers = headersPost, params = paramsPost )
if responsePost.status_code == 202: # everything went well!
videoIDLocation = responsePost.headers['Operation-Location']
print videoIDLocation
There are further examples on the internet and they all seem to work but replicating any of them never worked for me. Does anyone have any idea what could be wrong?
The Video Feature of Emotion API retires October 30th, so maybe you should change your procedure to screenshots anyways.
But for your question: The API returns you an URL where your results are accessible. You cannot open this URL in your browser, this will give you the notice of "invalid key", instead you need to call over python again this URL including your key.
I will post you my code how to get the score, I am using Python 3, so there might be some adjustments necessary. Only "tricky" point is getting the Operation ID, which is just the ID in the URL ( =location in my case) which leads to your request. Rest of the parameters like subscription key etc. is as before.
#extract operation ID from location-string
OID = location[67:]
bod = ""
try:
conn =
http.client.HTTPSConnection('westus.api.cognitive.microsoft.com')
conn.request("GET", "/emotion/v1.0/operations/"+OID+"?%s" %params, bod, headers)
response = conn.getresponse()
data = response.read()
print(data)
conn.close()
except Exception as e:
print("[Errno {0}] {1}".format(e.errno, e.strerror))
Did you verify your API call is working using curl? Always prototype calls using curl first. If it works in curl but not in Python, use Fiddler to observe the API request and response.
I also found an answer in the following link, all steps are explained:
https://gigaom.com/2017/04/10/discover-your-customers-deepest-feelings-using-microsoft-facial-recognition/
I am implementing Coinbase's exchange API using custom auth in requests-python. The following code works with all the (authenticated) GET-based calls, but fails for all the authenticated POST-based calls (I haven't tried with DELETE or UPDATE verbs). I don't understand why the signature wouldn't work for both, because the payload is timestamp + method + path for GETs and timestamp + method + path + body for PUTs, so custom auth seems correct. Something is going wrong with adding the body and changing GET to POST. Thanks!
You can get your API keys for trying it out here: https://gdax.com/settings
import json, hmac, hashlib, time, requests, base64
from requests.auth import AuthBase
class CoinbaseAuth(AuthBase):
SIGNATURE_HTTP_HEADER = 'CB-ACCESS-SIGN'
TIMESTAMP_HTTP_HEADER = 'CB-ACCESS-TIMESTAMP'
KEY_HTTP_HEADER = 'CB-ACCESS-KEY'
PASSPHRASE_HTTP_HEADER = 'CB-ACCESS-PASSPHRASE'
def __init__(self, api_key, secret_key, passphrase):
self.api_key = api_key
self.secret_key = secret_key
self.passphrase = passphrase
def __call__(self, request):
#Add headers
request.headers[CoinbaseAuth.KEY_HTTP_HEADER] = self.api_key
request.headers[CoinbaseAuth.PASSPHRASE_HTTP_HEADER] = self.passphrase
timestamp = str(time.time())
request.headers[CoinbaseAuth.TIMESTAMP_HTTP_HEADER] = timestamp
#add signature
method = request.method
path = request.path_url
content = request.body
message = timestamp + method + path
if content:
message += content
hmac_key = base64.b64decode(self.secret_key)
sig = hmac.new(hmac_key, message, hashlib.sha256)
sig_b64 = sig.digest().encode("base64").rstrip("\n")
#Add signature header
request.headers[CoinbaseAuth.SIGNATURE_HTTP_HEADER] = sig_b64
return request
#Get your keys here: https://gdax.com/settings
key = 'KEY GOES HERE'
secret = 'SECRET GOES HERE'
passphrase = 'PASSPHRASE GOES HERE'
api_url = 'https://api.gdax.com:443/'
auth = CoinbaseAuth(API_KEY, API_SECRET, API_PASS)
#GETs work, shows account balances
r = requests.get(api_url + 'accounts', auth=auth)
print r.json()
#POSTs fail: {message: 'invalid signature'}
order = {}
order['size'] = 0.01
order['price'] = 100
order['side'] = 'buy'
order['product_id'] = 'BTC-USD'
r = requests.post(api_url + 'orders', data=json.dumps(order), auth=auth)
print r.json()
And the output:
GET call: 200: [{u'available': .......}]
POST call: 400: {u'message': u'invalid signature'}
EDIT: POSTing 'a' instead of valid JSON-encoded data results in the same signature error (rather than a JSON decoding error from the server), so I don't think it is the way I'm forming the data. Notably, if I omit the body -- request.post(..., data='',...) --- the server responds appropriately with {u'message': u'Missing product_id'}.
I don't know why, but if I change the data keyword argument to requests.post() to json it works:
r = requests.post(api_url + 'orders', json=order, auth=auth)
EDIT: The only thing that changes, AFAICT, is the content-type in the header is changed from text to JSON. So it is likely that or a unicode vs ASCII encoding issue. Here's the issue for the library that added this feature recently: https://github.com/kennethreitz/requests/issues/2025#issuecomment-46337236
I believe the content needs to be a json string with no spaces (this is what the node example does anyway). Maybe try this:
message += json.dumps(content).replace(' ', '')
I had the same exact problem until I looked at the public gdax API for nodeJS and found that they are using some additional headers that were not mentioned in the GDAX API docs. I added them and then it started working. See my answer to the following: GDAX API Always Returns Http 400 "Invalid Signature" Even though I do it exactly like in the API Doc