Bittrex REST API for Python, I want to create an order using API v3 https://api.bittrex.com/v3/orders - python-2.7

I need help to create orders using the bittrex version 3 REST API. I have the code below and I can't understand what is missing to work.
I can make other GET calls, but I cannot make this POST request.
I don't know how to deal with the passing of parameters.
Official documentation at https://bittrex.github.io/api/v3#tag-Orders.
def NewOrder(market, amount, price):
#print 'open sell v3', market
market = 'HEDG-BTC'#'BTC-'+market
uri = 'https://api.bittrex.com/v3/orders?'
params = {
'marketSymbol': 'BTC-HEDG',#'HEDG-BTC', #market
'direction': 'BUY',
'type': 'LIMIT',
'quantity': amount,
'limit': price,
'timeInForce': 'POST_ONLY_GOOD_TIL_CANCELLED',
'useAwards': True
}
timestamp = str(int(time.time()*1000))
Content = ""
contentHash = hashlib.sha512(Content.encode()).hexdigest()
Method = 'POST'
uri2 = buildURI(uri, params)
#uri2 = 'https://api.bittrex.com/v3/orders?direction=BUY&limit=0.00021&marketSymbol=HEDG-BTC&quantity=1.1&timeInForce=POST_ONLY_GOOD_TIL_CANCELLED&type=LIMIT&useAwards=True'
#print uri2
PreSign = timestamp + uri2 + Method + contentHash# + subaccountId
#print PreSign
Signature = hmac.new(apisecret, PreSign.encode(), hashlib.sha512).hexdigest()
headers = {
'Api-Key' : apikey,
'Api-Timestamp' : timestamp,
'Api-Content-Hash': contentHash,
'Api-Signature' : Signature
}
r = requests.post(uri2, data={}, headers=headers, timeout=11)
return json.loads(r.content)
NewOrder('HEDG', 1.1, 0.00021)
And my error message:
{u'code': u'BAD_REQUEST', u'data': {u'invalidRequestParameter': u'direction'}, u'detail': u'Refer to the data field for specific field validation failures.'}

It seems from the documentation that this body is expected by the api as json data:
{
"marketSymbol": "string",
"direction": "string",
"type": "string",
"quantity": "number (double)",
"ceiling": "number (double)",
"limit": "number (double)",
"timeInForce": "string",
"clientOrderId": "string (uuid)",
"useAwards": "boolean"
}
and you are setting these values as url params that's the issue.
you need to do this:
uri = 'https://api.bittrex.com/v3/orders'
# NOTE >>>> please check that you provide all the required fields.
payload = {
'marketSymbol': 'BTC-HEDG',#'HEDG-BTC', #market
'direction': 'BUY',
'type': 'LIMIT',
'quantity': amount,
'limit': price,
'timeInForce': 'POST_ONLY_GOOD_TIL_CANCELLED',
'useAwards': True
}
# do rest of the stuffs as you are doing
# post payload as json data with the url given in doc
r = requests.post(uri, json=payload, headers=headers, timeout=11)
print(r.json())
If you still have issues let us know. If it works then please mark answer as accepted.
Hope this helps.

I made the following modifications to the code but started to give error in 'Content-Hash'
I'm assuming that some parameters are optional so they are commented.
def NewOrder(market, amount, price):
market = 'BTC-'+market
uri = 'https://api.bittrex.com/v3/orders'
payload = {
'marketSymbol': market,
'direction': 'BUY',
'type': 'LIMIT',
'quantity': amount,
#"ceiling": "number (double)",
'limit': price,
'timeInForce': 'POST_ONLY_GOOD_TIL_CANCELLED',
#"clientOrderId": "string (uuid)",
'useAwards': True
}
#ceiling (optional, must be included for ceiling orders and excluded for non-ceiling orders)
#clientOrderId (optional) client-provided identifier for advanced order tracking
timestamp = str(int(time.time()*1000))
Content = ''+json.dumps(payload, separators=(',',':'))
print Content
contentHash = hashlib.sha512(Content.encode()).hexdigest()
Method = 'POST'
#uri2 = buildURI(uri, payload)#line not used
print uri
#PreSign = timestamp + uri2 + Method + contentHash# + subaccountId
PreSign = timestamp + uri + Method + contentHash# + subaccountId
print PreSign
Signature = hmac.new(apisecret, PreSign.encode(), hashlib.sha512).hexdigest()
headers = {
'Api-Key' : apikey,
'Api-Timestamp' : timestamp,
'Api-Content-Hash': contentHash,
'Api-Signature' : Signature
}
r = requests.post(uri, json=payload, headers=headers, timeout=11)
print(r.json())
return json.loads(r.content)
NewOrder('HEDG', 1.5, 0.00021)
{u'code': u'INVALID_CONTENT_HASH'}

Bittrex API via requests package PYTHON
import hmac
import hashlib
import time, requests
nonce = str(int(time.time() * 1000))
content_hash = hashlib.sha512(''.encode()).hexdigest()
signature = hmac.new(
'<SECRET_KEY>'.encode(),
''.join([nonce, url, 'GET', content_hash]).encode(),
hashlib.sha512
).hexdigest()
headers = {
'Api-Timestamp': nonce,
'Api-Key': '<API_KEY>',
'Content-Type': 'application/json',
'Api-Content-Hash': content_hash,
'Api-Signature': signature
}
result = requests.get(url=url, headers=headers)

Related

Power BI Iterative API Loop

I am attempting (and can successfully do so) to connect to an API and loop through several iterations of the API call in order to grab the next_page value, put it in a list and then call the list.
Unfortunately, when this is published to the PBI service I am unable to refresh there and indeed 'Data Source Settings' tells me I have a 'hand-authored query'.
I have attempted to follow Chris Webbs' blog post around the usage of query parameters and relative path, but if I use this I just get a constant loop of the first page that's hit.
The Start Epoch Time is a helper to ensure I only grab data less than 3 months old.
let
iterations = 10000, // Number of MAXIMUM iterations
url = "https://www.zopim.com/api/v2/" & "incremental/" & "chats?fields=chats(*)" & "&start_time=" & Number.ToText( StartEpochTime ),
FnGetOnePage =
(url) as record =>
let
Source1 = Json.Document(Web.Contents(url, [Headers=[Authorization="Bearer MY AUTHORIZATION KEY"]])),
data = try Source1[chats] otherwise null, //get the data of the first page
next = try Source1[next_page] otherwise null, // the script ask if there is another page*//*
res = [Data=data, Next=next]
in
res,
GeneratedList =
List.Generate(
()=>[i=0, res = FnGetOnePage(url)],
each [i]<iterations and [res][Data]<>null,
each [i=[i]+1, res = FnGetOnePage([res][Next])],
each [res][Data])
Lookups
If Source1 exists, but [chats] may not, you can simplify
= try Source1[chats] otherwise null
to
= Source1[chats]?
Plus it you don't lose non-lookup errors.
m-spec-operators
Chris Web Method
should be something closer to this.
let
Headers = [
Accept="application/json"
],
BaseUrl = "https://www.zopim.com", // very important
Options = [
RelativePath = "api/v2/incremental/chats",
Headers = [
Accept="application/json"
],
Query = [
fields = "chats(*)",
start_time = Number.ToText( StartEpocTime )
],
Response = Web.Contents(BaseUrl, Options),
Result = Json.Document(Response) // skip if it's not JSON
in
Result
Here's an example of a reusable Web.Contents function
helper function
let
/*
from: <https://github.com/ninmonkey/Ninmonkey.PowerQueryLib/blob/master/source/WebRequest_Simple.pq>
Wrapper for Web.Contents returns response metadata
for options, see: <https://learn.microsoft.com/en-us/powerquery-m/web-contents#__toc360793395>
Details on preventing "Refresh Errors", using 'Query' and 'RelativePath':
- Not using Query and Relative path cause refresh errors:
<https://blog.crossjoin.co.uk/2016/08/23/web-contents-m-functions-and-dataset-refresh-errors-in-power-bi/>
- You can opt-in to Skip-Test:
<https://blog.crossjoin.co.uk/2019/04/25/skip-test-connection-power-bi-refresh-failures/>
- Debugging and tracing the HTTP requests
<https://blog.crossjoin.co.uk/2019/11/17/troubleshooting-web-service-refresh-problems-in-power-bi-with-the-power-query-diagnostics-feature/>
update:
- MaybeErrResponse: Quick example of parsing an error result.
- Raw text is returned, this is useful when there's an error
- now response[json] does not throw, when the data isn't json to begin with (false errors)
*/
WebRequest_Simple
= (
base_url as text,
optional relative_path as nullable text,
optional options as nullable record
)
as record =>
let
headers = options[Headers]?, //or: ?? [ Accept = "application/json" ],
merged_options = [
Query = options[Query]?,
RelativePath = relative_path,
ManualStatusHandling = options[ManualStatusHandling]? ?? { 400, 404, 406 },
Headers = headers
],
bytes = Web.Contents(base_url, merged_options),
response = Binary.Buffer(bytes),
response_metadata = Value.Metadata( bytes ),
status_code = response_metadata[Response.Status]?,
response_text = Text.Combine( Lines.FromBinary(response,null,null, TextEncoding.Utf8), "" ),
json = Json.Document(response),
IsJsonX = not (try json)[HasError],
Final = [
request_url = metadata[Content.Uri](),
response_text = response_text,
status_code = status_code,
metadata = response_metadata,
IsJson = IsJsonX,
response = response,
json = if IsJsonX then json else null
]
in
Final,
tests = {
WebRequest_Simple("https://httpbin.org", "json"), // expect: json
WebRequest_Simple("https://www.google.com"), // expect: html
WebRequest_Simple("https://httpbin.org", "/headers"),
WebRequest_Simple("https://httpbin.org", "/status/codes/406"), // exect 404
WebRequest_Simple("https://httpbin.org", "/status/406"), // exect 406
WebRequest_Simple("https://httpbin.org", "/get", [ Text = "Hello World"])
},
FinalResults = Table.FromRecords(tests,
type table[
status_code = Int64.Type, request_url = text,
metadata = record,
response_text = text,
IsJson = logical, json = any,
response = binary
],
MissingField.Error
)
in
FinalResults

Python script for creating Space on Cloud Confluence

I have over 700 Projects for which I have to create Spaces on Confluence Cloud. Doing this manually is not feasible. Have to come up with some script or tool that reads the information from Text File and creates the spaces. I have programming background - Python and Java. Can someone suggest a solution for achieving this please?
Here is the code snippet for reading the space and page names from excel and creating them in Confluence cloud -
import requests
import json
from requests.auth import HTTPBasicAuth
from openpyxl import load_workbook
from collections import defaultdict
filename = "path/PjtExport.xlsx"
wb = load_workbook(filename)
sheet = wb["Sheet1"]
confdict = defaultdict(list)
for i1 in range(2,10) :
if(str(sheet.cell(row=i1, column=1).value) != "None") :
spaceName = str(sheet.cell(row=i1, column=1).value)
keyName = spaceName.replace(" ","")
#print(keyName)
if not(confdict.keys().__contains__(spaceName)):
confdict.setdefault(keyName,spaceName)
#print(spaceName)
url = 'https://domain.atlassian.net/wiki/rest/api/space'
auth = HTTPBasicAuth('xxx#yyy.com', 'abcabcabc')
headers = {
"Accept": "application/json",
"Content-Type": "application/json"
}
payload = json.dumps({
"key": keyName,
"name": spaceName,
"description": {
"plain": {
"value": "Test space created in Python - XL Int",
"representation": "storage"
}
},
})
response = requests.request(
"POST",
url,
data=payload,
headers=headers,
auth=auth
)
res_data = response.json()
spaceID = str((res_data["homepage"]["id"]))
pageName = str(sheet.cell(row=i1, column=2).value)
url = "https://domain.atlassian.net/wiki/rest/api/content/aaaa/pagehierarchy/copy"
auth = HTTPBasicAuth('xxx#yyy.com', 'abcabcabc')
headers = {
"Content-Type": "application/json"
}
payload = json.dumps({
"copyAttachments": True,
"copyPermissions": True,
"copyProperties": True,
"copyLabels": True,
"copyCustomContents": True,
"destinationPageId": spaceID,
"titleOptions": {
"prefix": pageName + " ",
"replace": "",
"search": ""
}
})
response = requests.request(
"POST",
url,
data=payload,
headers=headers,
auth=auth
)
page_data = response.json()
#spaceID = str((res_data["homepage"]["id"]))
print(page_data)

How to retrieve multiple items from Dynamo DB using AWS lambda

How to get multiple items from DB. the below code throws me an error as it fetches only one item. I am retrieving the items based on email value.
import json
import os
import boto3
import decimalencoder
dynamodb = boto3.resource('dynamodb')
def get(event, context):
table = dynamodb.Table(os.environ['DYNAMODB_TABLE'])
# fetch a person from the database
result = table.get_item(
Key={
'email': event['pathParameters']['email']
}
)
# create a response
response = {
"statusCode": 200,
"body": json.dumps(result['Item'], cls=decimalencoder.DecimalEncoder),
"headers": {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Credentials": "true"
}
}
return response
To retrive multiple rows from db, first query on id you want data to be filtered.
Then maintain a list to store all row values in it.
def lambda_handler(event,context):
item = table.query(
KeyConditionExpression=Key('hubID').eq(hubId)
)
if (item["Count"] == 0):
response = {"msg": "Item not exist, can't perform READ"}
else:
i = 1
lst = []
while i < item["Count"]:
response = {
"hubId" : item["Items"][i]["hubID"],
"deviceState": int(item["Items"][i]["deviceState"]),
"deviceId": item["Items"][i]["deviceID"],
"deviceType": item["Items"][i]["deviceType"],
"intensity": int(item["Items"][i]["intensity"])
}
lst.append(response)
i += 1
print(lst)
response = lst
return response

Google Maps Geolocation API returns the latitude and longitude of my server

During my testing the Geolocation API use to return proper result.
But in deployment on AWS it is returning me the IP address of Virginia where my EC2 instances are located.
"cellId": 27193,
"locationAreaCode": 17007,
"mobileCountryCode": 404,
"mobileNetworkCode": 20
Result:
"lat": 19.2019619,
"lng": 73.1063466
But on AWs it returns:
"lat": 39.043756699999996
"lng": -77.4874416
params = {
"key": SERVER_KEY
}
data = json.dumps({
"cellTowers": [
{
"cellId": cid,
"locationAreaCode": lac,
"mobileCountryCode": mcc,
"mobileNetworkCode": mnc
}
]
})
log.info(params)
log.info(data)
request = requests.post(HOST_URL, params=params, data=data)
# print(request.text)
# print(request.status_code)
if request.status_code == 200:
response = json.loads(request.text)
latitude = response["location"]["lat"]
longitude = response["location"]["lng"]
return {
"latitude": latitude,
"longitude": longitude
}
else:
error_data = request.text
log.error("Error Occurred in Finding Cell Tower Location")
log.error(request.text)
log.error(json.dumps(params))
send_error_notification(error_data)
return None
Answer is so simple and how silly of me assuming that not adding header would not affect me.
By just adding the header with application/json everything is working like a charm.
params = {
"key": SERVER_KEY
}
data = json.dumps({
"considerIp": False,
"cellTowers": [
{
"cellId": cid,
"locationAreaCode": lac,
"mobileCountryCode": mcc,
"mobileNetworkCode": mnc
}
]
})
headers = {
'content-type': "application/json",
'cache-control': "no-cache"
}
log.info(params)
log.info(data)
request = requests.post(HOST_URL, params=params, data=data, headers=headers)

Mock Stripe Methods in Python for testing

So I am trying to mock all the stripe web hooks in the method so that I can write the Unit test for it. I am using the mock library for mocking the stripe methods. Here is the method I am trying to mock:
class AddCardView(APIView):
"""
* Add card for the customer
"""
permission_classes = (
CustomerPermission,
)
def post(self, request, format=None):
name = request.DATA.get('name', None)
cvc = request.DATA.get('cvc', None)
number = request.DATA.get('number', None)
expiry = request.DATA.get('expiry', None)
expiry_month, expiry_year = expiry.split("/")
customer_obj = request.user.contact.business.customer
customer = stripe.Customer.retrieve(customer_obj.stripe_id)
try:
card = customer.sources.create(
source={
"object": "card",
"number": number,
"exp_month": expiry_month,
"exp_year": expiry_year,
"cvc": cvc,
"name": name
}
)
# making it the default card
customer.default_source = card.id
customer.save()
except CardError as ce:
logger.error("Got CardError for customer_id={0}, CardError={1}".format(customer_obj.pk, ce.json_body))
return Response({"success": False, "error": "Failed to add card"})
else:
customer_obj.card_last_4 = card.get('last4')
customer_obj.card_kind = card.get('type', '')
customer_obj.card_fingerprint = card.get('fingerprint')
customer_obj.save()
return Response({"success": True})
This is the method for unit testing:
#mock.patch('stripe.Customer.retrieve')
#mock.patch('stripe.Customer.create')
def test_add_card(self,create_mock,retrieve_mock):
response = {
'default_card': None,
'cards': {
"count": 0,
"data": []
}
}
# save_mock.return_value = response
create_mock.return_value = response
retrieve_mock.return_value = response
self.api_client.client.login(username = self.username, password = self.password)
res = self.api_client.post('/biz/api/auth/card/add')
print res
Now stripe.Customer.retrieve is being mocked properly. But I am not able to mock customer.sources.create. I am really stuck on this.
This is the right way of doing it:
#mock.patch('stripe.Customer.retrieve')
def test_add_card_failure(self, retrieve_mock):
data = {
'name': "shubham",
'cvc': 123,
'number': "4242424242424242",
'expiry': "12/23",
}
e = CardError("Card Error", "", "")
retrieve_mock.return_value.sources.create.return_value = e
self.api_client.client.login(username=self.username, password=self.password)
res = self.api_client.post('/biz/api/auth/card/add', data=data)
self.assertEqual(self.deserialize(res)['success'], False)
Even though the given answer is correct, there is a way more comfortable solution using vcrpy. That is creating a cassette (record) once a given record does not exist yet. When it does, the mocking is done transparently and the record will be replayed. Beautiful.
Having a vanilla pyramid application, using py.test, my test now looks like this:
import vcr
# here we have some FactoryBoy fixtures
from tests.fixtures import PaymentServiceProviderFactory, SSOUserFactory
def test_post_transaction(sqla_session, test_app):
# first we need a PSP and a User existent in the DB
psp = PaymentServiceProviderFactory() # type: PaymentServiceProvider
user = SSOUserFactory()
sqla_session.add(psp, user)
sqla_session.flush()
with vcr.use_cassette('tests/casettes/tests.checkout.services.transaction_test.test_post_transaction.yaml'):
# with that PSP we create a new PSPTransaction ...
res = test_app.post(url='/psps/%s/transaction' % psp.id,
params={
'token': '4711',
'amount': '12.44',
'currency': 'EUR',
})
assert 201 == res.status_code
assert 'id' in res.json_body
IMO, the following method is better than the rest of the answers
import unittest
import stripe
import json
from unittest.mock import patch
from stripe.http_client import RequestsClient # to mock the request session
stripe.api_key = "foo"
stripe.default_http_client = RequestsClient() # assigning the default HTTP client
null = None
false = False
true = True
charge_resp = {
"id": "ch_1FgmT3DotIke6IEFVkwh2N6Y",
"object": "charge",
"amount": 1000,
"amount_captured": 1000,
"amount_refunded": 0,
"billing_details": {
"address": {
"city": "Los Angeles",
"country": "USA",
},
"email": null,
"name": "Jerin",
"phone": null
},
"captured": true,
}
def get_customer_city_from_charge(stripe_charge_id):
# this is our function and we are writing unit-test for this function
charge_response = stripe.Charge.retrieve("foo-bar")
return charge_response.billing_details.address.city
class TestStringMethods(unittest.TestCase):
#patch("stripe.default_http_client._session")
def test_get_customer_city_from_charge(self, mock_session):
mock_response = mock_session.request.return_value
mock_response.content.decode.return_value = json.dumps(charge_resp)
mock_response.status_code = 200
city_name = get_customer_city_from_charge("some_id")
self.assertEqual(city_name, "Los Angeles")
if __name__ == '__main__':
unittest.main()
Advantages of this method
You can generate the corresponding class objects (here, the charge_response variable is a type of Charge--(source code))
You can use the dot (.) operator over the response (as we can do with real stripe SDK)
dot operator support for deep attributes