How do I URL encode this - python

Need this:
POST&https%3A%2F%2Fsecure.trademe.co.nz%2FOauth%2FRequestToken&oauth_callback%3Dhttp%253A%252F%252Fwww.website-tm-access.co.nz%252Ftrademe-callback%26oauth_consumer_key%3DC74CD73FDBE37D29BDD21BAB54BC70E422%26oauth_nonce%3D7O3kEe%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1285532322%26oauth_version%3D1.0%26scope%3DMyTradeMeRead%252CMyTradeMeWrite
Myattempt:
New_base_string ="POST&https%3A%2F%2Fsecure.trademe.co.nz%2FOauth%2FRequestToken&oauth_callback%3Dhttp%253A%252F%252Fwww.website-tm-access.co.nz%252Ftrademe-callback%26oauth_consumer_key%" + str(consumer_key) +"3DC74CD73FDBE37D29BDD21BAB54BC70E422%26oauth_nonce%3" + str(nonce) + "%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3" + str(time) + "%26oauth_version%3D1.0%26scope%3DMyTradeMeRead%252CMyTradeMeWrite"
I just tried to append it to the end, will this work or will i need to append to a list and then encode?
so like this:
headers = { my_variable + other_variable }
authorization = '5C82CC6BC7C6472154FBC9CAB24A29A2 ' + ', '.join([key + '="' + urllib.parse.quote_plus(str(value)) + '"' for key, value in headers.items()])

General
If you want to URL encode parameters to your POST request the best way is:
import urllib
f = { 'eventName' : 'myEvent',
'eventDescription' : 'cool event',
'url' : 'http://www.google.com'}
print 'POST&%s' % urllib.urlencode(f)
Output:
POST&eventName=myEvent&url=http%3A%2F%2Fwww.google.com&eventDescription=cool+event
with Dictionary its not ordered if you want to order it just use a list
import urllib
f = [ ('eventName', 'myEvent'),
('eventDescription', 'cool event'),
('url', 'http://www.google.com')]
print 'POST&%s' % urllib.urlencode(f)
Output
POST&eventName=myEvent&eventDescription=cool+event&url=http%3A%2F%2Fwww.google.com
How to get your need this string (Python 3.5)
While the general example is tested in python 2.7, I wrote your example with python 3.5 code.
import urllib.parse
method = "POST"
url = "https://secure.trademe.co.nz/Oauth/RequestToken"
params = [('oauth_callback', 'http://www.website-tm-access.co.nz/trademe-callback'),
('oauth_consumer_key', 'C74CD73FDBE37D29BDD21BAB54BC70E422'),
('oauth_nonce', '7O3kEe'),
('oauth_signature_method', 'HMAC-SHA1'),
('oauth_timestamp', 1285532322),
('oauth_version', 1.0),
('scope', "MyTradeMeRead,MyTradeMeWrite")]
print('POST&%(url)s&%(params)s' % { 'url' : urllib.parse.quote_plus(url), 'params' : urllib.parse.quote_plus(urllib.parse.urlencode(params)) })
Output
POST&https%3A%2F%2Fsecure.trademe.co.nz%2FOauth%2FRequestToken&oauth_callback%3Dhttp%253A%252F%252Fwww.website-tm-access.co.nz%252Ftrademe-callback%26oauth_consumer_key%3DC74CD73FDBE37D29BDD21BAB54BC70E422%26oauth_nonce%3D7O3kEe%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1285532322%26oauth_version%3D1.0%26scope%3DMyTradeMeRead%252CMyTradeMeWrite

Related

huobi working python 3.6 example (including signature)

Working example to generate a valid url (including signature) for the Huobi API.
In the Huobi API documenation there is no explicit example that allows you to verify your signature creation method step by step.
My intention is to create that here, but I need help, because I haven't managed yet.
Try to order using huobi api
First, I succeed to get account information
from datetime import datetime
import requests
import json
import hmac
import hashlib
import base64
from urllib.parse import urlencode
#Get all Accounts of the Current User
#apiAccessKey = hb_access, apiSecretKey = hb_secret
timestamp = str(datetime.utcnow().isoformat())[0:19]
params = urlencode({'AccessKeyId': hb_access,
'SignatureMethod': 'HmacSHA256',
'SignatureVersion': '2',
'Timestamp': timestamp
})
method = 'GET'
endpoint = '/v1/account/accounts'
base_uri = 'api.huobi.pro'
pre_signed_text = method + '\n' + base_uri + '\n' + endpoint + '\n' + params
hash_code = hmac.new(hb_secret.encode(), pre_signed_text.encode(), hashlib.sha256).digest()
signature = urlencode({'Signature': base64.b64encode(hash_code).decode()})
url = 'https://' + base_uri + endpoint + '?' + params + '&' + signature
# url = 'https://' + base_uri + endpoint2 + '?' + params + '&' + signature
response = requests.request(method, url)
accts = json.loads(response.text)
print(accts)
it gives :
{'status': 'ok', 'data': [{'id': 1153465, 'type': 'spot', 'subtype': '', 'state': 'working'}, {'id': 1170797, 'type': 'otc', 'subtype': '', 'state': 'working'}]}
but, I have problem with market order.
want to look matchresults :
here is the discription from the website
https://alphaex-api.github.io/openapi/spot/v1/en/#search-match-results
GET /v1/order/matchresults
Parameter DataType Required Default Description Value Range
symbol string true btcusdt, bccbtc.Refer to
I know I should add symbol parameter, but I don't know how I do that,,,
and my code :
timestamp = str(datetime.utcnow().isoformat())[0:19]
params = urlencode({'AccessKeyId': hb_access,
'SignatureMethod': 'HmacSHA256',
'SignatureVersion': '2',
'Timestamp': timestamp,
})
method = 'GET'
base_uri = 'api.huobi.pro'
enpoint ='/v1/order/matchresults'
pre_signed_text = base_uri + '\n' + endpoint + '\n' + params
hash_code = hmac.new(hb_secret.encode(), pre_signed_text.encode(), hashlib.sha256).digest()
signature = urlencode({'Signature': base64.b64encode(hash_code).decode()})
url = 'https://'+base_uri + endpoint +'?'+params+'&'+signature
resp = requests.request(method, url)
resp.json()
it gives :
{'status': 'error',
'err-code': 'api-signature-not-valid',
'err-msg': 'Signature not valid: Verification failure [校验失败]',
'data': None}
I need help...
and another question is :
is way to make Sinature different with using Get method from using POST method?
like placing market order(POST /v1/order/orders/place), when I request using POST do I need to give different Signature?
To get exact symbol you have to provide required parameters in param variable
params = urlencode({'AccessKeyId': hb_access,
'SignatureMethod': 'HmacSHA256',
'SignatureVersion': '2',
'Timestamp': timestamp,
"symbol": "btcusdt" # allowed symbols: GET /v1/common/symbols
})
url variable:
https://api.huobi.pro/v1/order/matchresults?AccessKeyId=39****-b******-4*****-3****&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2022-09-26T19%3A09%3A16&symbol=btcusdt&Signature=1K**************************
Output:
{'status': 'ok', 'data': []}
Here is my way adding parameters and making request:
def huobi(endpoint: str, extra_params: dict={}, AccessKeyId: str=None, SecretKey: str=None) -> dict:
AccessKeyId = 'xxxxxx-xxxxxx-xxxxxx-xxxx' # tmp
SecretKey = 'xxxxxx-xxxxxx-xxxxxx-xxxx' # tmp
timestamp = str(datetime.utcnow().isoformat())[0:19]
standart_params = {
'AccessKeyId': AccessKeyId,
'SignatureMethod': 'HmacSHA256',
'SignatureVersion': '2',
'Timestamp': timestamp
}
params = dict(standart_params, **extra_params)
params_url_enc = urlencode(
sorted(params.items(), key=lambda tup: tup[0])
)
pre_signed = 'GET\n'
pre_signed += 'api.huobi.pro\n'
pre_signed += f'{endpoint}\n'
pre_signed += params_url_enc
sig_bin = hmac.new(
SecretKey.encode(),
pre_signed.encode(),
hashlib.sha256
).digest()
sig_b64_bytes = base64.b64encode(sig_bin)
sig_b64_str = sig_b64_bytes.decode()
signature = urlencode({'Signature': sig_b64_str})
url = f'https://api.huobi.pro{endpoint}?'
url += params_url_enc + '&'
url += signature
return requests.get(url).json()
endpoint = "/v2/account/valuation"
extra_params = {
"accountType": "1",
"valuationCurrency": "BTC"
}
print(huobi(endpoint=endpoint, extra_params=extra_params))

json response to python variable

In the following code (a html response), do I need to remove the "M18.high_52 = {" in the beginning and the "}" (in the very end) in order to assign it under a python json variable? Thanks!
Update:
I just want to get the securityCode and securityShortName. Both already done and I just want to see it could be simply it and not using the
x = r.text.replace("M18.high_52 = " ,"")
to assign to json.
M18.high_52 = {
"stockBeans" : [
{
"securityCode" : "00176",
"yearHigh" : "0.218",
"yearLow" : "0.121",
"percentageChange" : 14.737,
"priceChange" : 0.028,
"securityShortName" : "SUPERACTIVE GP",
"securityNameGCCS" : "先機企業集團",
"previousClosingPrice" : "0.19",
"nominalPrice" : "0.218",
"sharesTraded" : "400000",
"turnover" : "80726",
"highPrice" : "0.22",
"lowPrice" : "0.19"
}
,{
"securityCode" : "00532",
"yearHigh" : "0.71",
"yearLow" : "0.49",
"percentageChange" : 20.339,
"priceChange" : 0.12,
"securityShortName" : "WKK INTL (HOLD)",
"securityNameGCCS" : "王氏港建國際",
"previousClosingPrice" : "0.59",
"nominalPrice" : "0.71",
"sharesTraded" : "1122000",
"turnover" : "749480",
"highPrice" : "0.72",
"lowPrice" : "0.63"
}
],
"stockBeans.size" : 37
}
Update:
import json
import requests
###
def update52wHigh():
r = requests.get("http://money18.on.cc/js/real/52highlow/high_securityCode_b5_asc.js")
r.encoding = 'big5-hkscs'
x = r.text.replace("M18.high_52 = " ,"")
j = json.loads(x)
print (j["stockBeans"][0]["securityNameGCCS"])
importList = []
stockList = []
x=0
for stockBean in j["stockBeans"]:
stockName = stockBean["securityNameGCCS"]
stockNo = stockBean["securityCode"]
stockPrice = stockBean["nominalPrice"]
stockTurnover = stockBean["turnover"]
stockPercentageChange = stockBean["percentageChange"]
print (stockNo + " " +stockName)
if float(stockPrice) > 1:
stockList.append([])
stockList[x].append(stockNo)
stockList[x].append(stockPrice)
importList.append((stockNo,stockName,stockPrice,stockTurnover,stockPercentageChange))
x=x+1
update52wHigh()
No need to remove anything..You already have a response
This show work
import json
import requests
string_res = response.read().decode('utf-8')
json_object = json.loads(string_res)

Bitmex Api for authorization

This is what i have try:
import time
import json
import hashlib
import hmac
from urllib.parse import urlparse
import requests
from datetime import datetime, timedelta
from pprint import pprint
def generate_signature(secret, verb, url, expires, data):
"""Generate a request signature compatible with BitMEX."""
# Parse the url so we can remove the base and extract just the path.
parsedURL = urlparse(url)
path = parsedURL.path
if parsedURL.query:
path = path + '?' + parsedURL.query
if isinstance(data, (bytes, bytearray)):
data = data.decode('utf8')
print("Computing HMAC: %s" % verb + path + str(expires) + data)
message = verb + path + str(expires) + data
signature = hmac.new(bytes(secret, 'utf8'), bytes(message, 'utf8'), digestmod=hashlib.sha256).hexdigest()
return signature
# Or you might generate it like so:
# expires = int(round(time.time()) + 5)
data = {
'filter': {"symbol": "XBTUSD"},
'columns': [],
'count': 100
'start': 1,
'reverse': "true",
'startTime': str(datetime.now() - timedelta(minutes=50)),
'endTime': str(datetime.now())
}
verb = 'GET'
path = '/api/v1/position'
time_in_epoch = int(datetime.timestamp(datetime.now() + timedelta(hours=.5)))
print("========",time_in_epoch, int(round(time.time()) + 1800))
expires = time_in_epoch
gen_signat = generate_signature('api-sceret', verb, path, expires, json.dumps(data))
URL_get_data = "http://www.bitmex.com/api/v1/position"
headers = {
'api-expires': str(expires),
'api-key': "api-key",
'api-signature': str(gen_signat),
}
response = requests.get(URL_get_data, headers=headers, data= data).json()
Still showing error:
{'error': {'message': 'Signature not valid.', 'name': 'HTTPError'}}
If I pass this gen_signat = generate_signature('api-sceret', verb, path, expires, data) the showing reponse<200> but returns empty list.
Looks like you're basing on this Bitmex sample. Please note that data must be JSON without whitespace between keys. The default separators value for json.dumps is (', ', ': '), so you need to change your code to use (',', ':'). It should be gen_signat = generate_signature('api-sceret', verb, path, expires, json.dumps(data,separators=(',', ':'))).

Signed request with python to binance future

I have been struggling to send a signed request to binance future using signature.
I found that example code on StackOverflow ("Binance API call with SHA56 and Python requests") and an answer has been given to it mentioning to use hmac
as below: but unfortunately i still don't see how to write this example. Could anyone show how the code of this example should look like? i am really uncomfortable with signed request. Thanks a lot for your understanding and your help advice given:
params = urlencode({
"signature" : hashedsig,
"timestamp" : servertimeint,
})
hashedsig = hmac.new(secret.encode('utf-8'), params.encode('utf-8'), hashlib.sha256).hexdigest()
Original example:
import requests, json, time, hashlib
apikey = "myactualapikey"
secret = "myrealsecret"
test = requests.get("https://api.binance.com/api/v1/ping")
servertime = requests.get("https://api.binance.com/api/v1/time")
servertimeobject = json.loads(servertime.text)
servertimeint = servertimeobject['serverTime']
hashedsig = hashlib.sha256(secret)
userdata = requests.get("https://api.binance.com/api/v3/account",
params = {
"signature" : hashedsig,
"timestamp" : servertimeint,
},
headers = {
"X-MBX-APIKEY" : apikey,
}
)
print(userdata)
The proper way would be:
apikey = "myKey"
secret = "mySecret"
servertime = requests.get("https://api.binance.com/api/v1/time")
servertimeobject = json.loads(servertime.text)
servertimeint = servertimeobject['serverTime']
params = urlencode({
"timestamp" : servertimeint,
})
hashedsig = hmac.new(secret.encode('utf-8'), params.encode('utf-8'),
hashlib.sha256).hexdigest()
userdata = requests.get("https://api.binance.com/api/v3/account",
params = {
"timestamp" : servertimeint,
"signature" : hashedsig,
},
headers = {
"X-MBX-APIKEY" : apikey,
}
)
print(userdata)
print(userdata.text)
Make sure to put the signature as the last parameter or the request will return [400]...
Incorrect:
params = {
"signature" : hashedsig,
"timestamp" : servertimeint,
}
Correct:
params = {
"timestamp" : servertimeint,
"signature" : hashedsig,
}
At the time of writing, Binance themselves are mainting a repo with some examples*, using the requests library. Here is a sample in case the link goes down or is moved:
import hmac
import time
import hashlib
import requests
from urllib.parse import urlencode
KEY = ''
SECRET = ''
# BASE_URL = 'https://fapi.binance.com' # production base url
BASE_URL = 'https://testnet.binancefuture.com' # testnet base url
''' ====== begin of functions, you don't need to touch ====== '''
def hashing(query_string):
return hmac.new(SECRET.encode('utf-8'), query_string.encode('utf-8'), hashlib.sha256).hexdigest()
def get_timestamp():
return int(time.time() * 1000)
def dispatch_request(http_method):
session = requests.Session()
session.headers.update({
'Content-Type': 'application/json;charset=utf-8',
'X-MBX-APIKEY': KEY
})
return {
'GET': session.get,
'DELETE': session.delete,
'PUT': session.put,
'POST': session.post,
}.get(http_method, 'GET')
# used for sending request requires the signature
def send_signed_request(http_method, url_path, payload={}):
query_string = urlencode(payload)
# replace single quote to double quote
query_string = query_string.replace('%27', '%22')
if query_string:
query_string = "{}&timestamp={}".format(query_string, get_timestamp())
else:
query_string = 'timestamp={}'.format(get_timestamp())
url = BASE_URL + url_path + '?' + query_string + '&signature=' + hashing(query_string)
print("{} {}".format(http_method, url))
params = {'url': url, 'params': {}}
response = dispatch_request(http_method)(**params)
return response.json()
# used for sending public data request
def send_public_request(url_path, payload={}):
query_string = urlencode(payload, True)
url = BASE_URL + url_path
if query_string:
url = url + '?' + query_string
print("{}".format(url))
response = dispatch_request('GET')(url=url)
return response.json()
response = send_signed_request('POST', '/fapi/v1/order', params)
print(response)
Some additional thoughts from myself:
You can also use a new library also from Binance called Binance connector. It is a bit new, it has some issues, but it can do the basic operations without you worrying about signed requests.
I wouldn't use serverTime because that means you need to make an additional request and networks can be slow, I'd follow this example and use the int(time.time() * 1000) you may not even need the function.
I purposedly used the POST example, because this is more complicated as you need to also encode and hash your custom parameters
At the time of writing, v3 is the latest version
Hope it helps.
* https://github.com/binance/binance-signature-examples/blob/master/python/futures.py

URL request emulating curl --data-binary

I want to send a URL request equivalent to using to json objects in the post data, separated by newline.
This is for indexing two items in bulk for Elasticsearch.
This works fine:
curl -XPOST 'localhost:9200/myindex/mydoc?pretty=true' --data-binary #myfile.json
where myfile.json:
{"index": {"_parent": "btaCovzjQhqrP4s3iPjZKQ"}}
{"title": "hello"}
{"index": {"_parent": "btaCovzjQhqrP4s3iPjZKQ"}}
{"title": "world"}
When I try it using:
req = urllib2.Request(url,data=
json.dumps({"index": {"_parent": "btaCovzjQhqrP4s3iPjZKQ"}}) + "\n" +
json.dumps({"title":"hello"}) + "\n" +
json.dumps({"index": {"_parent": "btaCovzjQhqrP4s3iPjZKQ"}}) + "\n" +
json.dumps({"title":"world"})
I get:
HTTP Error 500: Internal Server Error
The "HTTP Error 500" may be from forgetting to include an index name or index type.
Also: for bulk inserts, elasticsearch requires a trailing "\n" character after the last record, or it won't insert that record.
Try:
import urllib2
import json
url = 'http://localhost:9200/myindex/mydoc/_bulk?pretty=true'
data = json.dumps({"index": {"_parent": "btaCovzjQhqrP4s3iPjZKQ"}}) + "\n" + json.dumps({"title":"hello"}) + "\n" + json.dumps({"index": {"_parent": "btaCovzjQhqrP4s3iPjZKQ"}}) + "\n" + json.dumps({"title":"world"})
req = urllib2.Request(url,data=data+"\n")
f = urllib2.urlopen(req)
print f.read()
Or, with some refactoring:
import urllib2
import json
url = 'http://localhost:9200/myindex/mydoc/_bulk?pretty=true'
data = [
{"index": {"_parent": "btaCovzjQhqrP4s3iPjZKQ"}},
{"title":"hello"},
{"index": {"_parent": "btaCovzjQhqrP4s3iPjZKQ"}},
{"title":"world"}
]
encoded_data = "\n".join(map(json.dumps,data)) + "\n"
req = urllib2.Request(url,data=encoded_data)
f = urllib2.urlopen(req)
print f.read()
The usecase for me is actually a bulk_index request for ElasticSearch.
This is made a lot easier with rawes:
import rawes
es = rawes.Elastic('localhost:9200')
with open('myfile.json') as f:
lines = f.readlines()
es.post('someindex/sometype/_bulk', data=lines)

Categories

Resources