1
|
|
|
#! /usr/bin/env python |
2
|
|
|
"""API Wrapper for Bitcoin.de Trading API.""" |
3
|
|
|
|
4
|
|
|
import requests |
5
|
|
|
import time |
6
|
|
|
import json |
7
|
|
|
import hmac |
8
|
|
|
import hashlib |
9
|
|
|
import logging |
10
|
|
|
import codecs |
11
|
|
|
import decimal |
12
|
|
|
import inspect |
13
|
|
|
import urllib |
14
|
|
|
|
15
|
|
|
from urllib.parse import urlencode |
16
|
|
|
|
17
|
|
|
logging.basicConfig() |
18
|
|
|
log = logging.getLogger(__name__) |
19
|
|
|
requests_log = logging.getLogger("requests.packages.urllib3") |
20
|
|
|
requests_log.propagate = True |
21
|
|
|
|
22
|
|
|
__version__ = '4.0' |
23
|
|
|
|
24
|
|
|
class ParameterBuilder(object): |
25
|
|
|
'''To verify given parameters for API.''' |
26
|
|
|
def __init__(self, avail_params, given_params, uri): |
27
|
|
|
self.verify_keys_and_values(avail_params, given_params) |
28
|
|
|
self.params = given_params |
29
|
|
|
self.create_url(uri) |
30
|
|
|
|
31
|
|
|
def verify_keys_and_values(self, avail_params, given_params): |
32
|
|
|
for k, v in given_params.items(): |
33
|
|
|
if k not in avail_params: |
34
|
|
|
list_string = ', '.join(avail_params) |
35
|
|
|
raise KeyError("{} is not any of {}".format(k, list_string)) |
36
|
|
|
if k == 'trading_pair': |
37
|
|
|
self.error_on_invalid_value(v, self.TRADING_PAIRS) |
38
|
|
|
elif k == 'type': |
39
|
|
|
self.error_on_invalid_value(v, self.TRADE_TYPES) |
40
|
|
|
elif k == 'currency': |
41
|
|
|
self.error_on_invalid_value(v, self.CURRENCIES) |
42
|
|
|
elif k == 'seat_of_bank': |
43
|
|
|
self.error_on_invalid_value(v, self.BANK_SEATS) |
44
|
|
|
elif k in ['min_trust_level', 'trust_level']: |
45
|
|
|
self.error_on_invalid_value(v, self.TRUST_LEVELS) |
46
|
|
|
elif k == 'payment_option': |
47
|
|
|
self.error_on_invalid_value(v, self.PAYMENT_OPTIONS) |
48
|
|
|
elif k == 'state': |
49
|
|
|
caller = inspect.stack()[2][3] |
50
|
|
|
if caller in ["showMyOrders", "showMyOrderDetails"]: |
51
|
|
|
self.error_on_invalid_value(v, self.ORDER_STATES) |
52
|
|
|
elif caller in ["showMyTrades", "showMyTradesDetails"]: |
53
|
|
|
self.error_on_invalid_value(v, self.TRADE_STATES) |
54
|
|
|
|
55
|
|
|
def error_on_invalid_value(self, value, list): |
56
|
|
|
if value not in list: |
57
|
|
|
list_string = ', '.join(str(x) for x in list) |
58
|
|
|
raise ValueError("{} is not any of {}".format(value, list_string)) |
59
|
|
|
|
60
|
|
|
def create_url(self, uri): |
61
|
|
|
if self.params: |
62
|
|
|
self.encoded_string = urlencode(sorted(self.params.items())) |
63
|
|
|
self.url = uri + '?' + self.encoded_string |
64
|
|
|
else: |
65
|
|
|
self.encoded_string = '' |
66
|
|
|
self.url = uri |
67
|
|
|
|
68
|
|
|
|
69
|
|
|
TRADING_PAIRS = ['btceur', 'bcheur', 'etheur', 'btgeur', 'bsveur', 'ltceur', |
70
|
|
|
'iotabtc', 'dashbtc', 'gntbtc', 'ltcbtc'] |
71
|
|
|
ORDER_TYPES = ['buy', 'sell'] |
72
|
|
|
CURRENCIES = ['btc', 'bch', 'eth', 'btg', 'bsv', 'ltc', |
73
|
|
|
'iota', 'dash', 'gnt'] |
74
|
|
|
BANK_SEATS = ['AT', 'BE', 'BG', 'CH', 'CY', 'CZ', |
75
|
|
|
'DE', 'DK', 'EE', 'ES', 'FI', 'FR', |
76
|
|
|
'GB', 'GR', 'HR', 'HU', 'IE', 'IS', |
77
|
|
|
'IT', 'LI', 'LT', 'LU', 'LV', 'MT', |
78
|
|
|
'MQ', 'NL', 'NO', 'PL', 'PT', 'RO', |
79
|
|
|
'SE', 'SI', 'SK'] |
80
|
|
|
TRUST_LEVELS = ['bronze', 'silver', 'gold', 'platin'] |
81
|
|
|
TRADE_STATES = [-1, 0, 1] |
82
|
|
|
ORDER_STATES = [-2, -1, 0] |
83
|
|
|
PAYMENT_OPTIONS = [1, 2, 3] |
84
|
|
|
TRADE_TYPES = ['all', 'buy', 'sell', 'inpayment', |
85
|
|
|
'payout', 'affiliate', 'welcome_btc', |
86
|
|
|
'buy_yubikey', 'buy_goldshop', |
87
|
|
|
'buy_diamondshop', 'kickback', |
88
|
|
|
'outgoing_fee_voluntary'] |
89
|
|
|
|
90
|
|
|
def HandleRequestsException(e): |
91
|
|
|
"""Handle Exception from request.""" |
92
|
|
|
log.warning(e) |
93
|
|
|
|
94
|
|
|
|
95
|
|
|
def HandleAPIErrors(r): |
96
|
|
|
"""To handle Errors from BTCDE API.""" |
97
|
|
|
valid_status_codes = [200, 201, 204] |
98
|
|
|
if r.status_code not in valid_status_codes: |
99
|
|
|
content = r.json() |
100
|
|
|
errors = content.get('errors') |
101
|
|
|
log.warning('API Error Code: {}'.format(str(errors[0]['code']))) |
102
|
|
|
log.warning('API Error Message: {}'.format(errors[0]['message'])) |
103
|
|
|
log.warning('API Error URL: {}'.format(r.url)) |
104
|
|
|
return False |
105
|
|
|
else: |
106
|
|
|
return True |
107
|
|
|
|
108
|
|
|
class Connection(object): |
109
|
|
|
"""To provide connection credentials to the trading API""" |
110
|
|
|
def __init__(self, api_key, api_secret): |
111
|
|
|
self.api_key = api_key |
112
|
|
|
self.api_secret = api_secret |
113
|
|
|
# set initial self.nonce |
114
|
|
|
self.nonce = int(time.time() * 1000000) |
115
|
|
|
# Bitcoin.de API URI |
116
|
|
|
self.apihost = 'https://api.bitcoin.de' |
117
|
|
|
self.apiversion = 'v4' |
118
|
|
|
self.apibase = f'{self.apihost}/{self.apiversion}/' |
119
|
|
|
|
120
|
|
|
def build_hmac_sign(self, md5string, method, url): |
121
|
|
|
hmac_data = '#'.join([method, url, self.api_key, str(self.nonce), md5string]) |
122
|
|
|
hmac_signed = hmac.new(bytearray(self.api_secret.encode()), msg=hmac_data.encode(), digestmod=hashlib.sha256).hexdigest() |
123
|
|
|
return hmac_signed |
124
|
|
|
|
125
|
|
|
def set_header(self, url, method, encoded_string): |
126
|
|
|
# raise self.nonce before using |
127
|
|
|
self.nonce = int(time.time() * 1000000) |
128
|
|
|
if method == 'POST': |
129
|
|
|
md5_encoded_query_string = hashlib.md5(encoded_string.encode()).hexdigest() |
130
|
|
|
else: |
131
|
|
|
md5_encoded_query_string = hashlib.md5(b'').hexdigest() |
132
|
|
|
hmac_signed = self.build_hmac_sign(md5_encoded_query_string, |
133
|
|
|
method, url) |
134
|
|
|
# set header |
135
|
|
|
header = {'content-type': |
136
|
|
|
'application/x-www-form-urlencoded; charset=utf-8', |
137
|
|
|
'X-API-KEY': self.api_key, |
138
|
|
|
'X-API-NONCE': str(self.nonce), |
139
|
|
|
'X-API-SIGNATURE': hmac_signed } |
140
|
|
|
return header |
141
|
|
|
|
142
|
|
|
def send_request(self, url, method, header, encoded_string): |
143
|
|
|
if method == 'GET': |
144
|
|
|
r = requests.get(url, headers=(header), |
145
|
|
|
stream=True, verify=False) |
146
|
|
|
elif method == 'POST': |
147
|
|
|
r = requests.post(url, headers=(header), data=encoded_string, |
148
|
|
|
stream=True, verify=False) |
149
|
|
|
elif method == 'DELETE': |
150
|
|
|
r = requests.delete(url, headers=(header), |
151
|
|
|
stream=True, verify=False) |
152
|
|
|
return r |
|
|
|
|
153
|
|
|
|
154
|
|
|
def APIConnect(self, method, params): |
155
|
|
|
"""Transform Parameters to URL""" |
156
|
|
|
header = self.set_header(params.url, method, |
157
|
|
|
params.encoded_string) |
158
|
|
|
log.debug('Set Header: {}'.format(header)) |
159
|
|
|
try: |
160
|
|
|
r = self.send_request(params.url, method, header, |
161
|
|
|
params.encoded_string) |
162
|
|
|
# Handle API Errors |
163
|
|
|
if HandleAPIErrors(r): |
164
|
|
|
# get results |
165
|
|
|
result = r.json(parse_float=decimal.Decimal) |
166
|
|
|
else: |
167
|
|
|
result = {} |
168
|
|
|
except requests.exceptions.RequestException as e: |
169
|
|
|
HandleRequestsException(e) |
170
|
|
|
result = {} |
171
|
|
|
return result |
172
|
|
|
|
173
|
|
|
def addToAddressPool(self, currency, address, **args): |
174
|
|
|
"""Add address to pool""" |
175
|
|
|
uri = f'{self.apibase}{currency}/address' |
176
|
|
|
params = {'address': address} |
177
|
|
|
params.update(args) |
178
|
|
|
avail_params = ['address', 'amount_usages', 'comment'] |
179
|
|
|
p = ParameterBuilder(avail_params, params, uri) |
180
|
|
|
return self.APIConnect('POST', p) |
181
|
|
|
|
182
|
|
|
def removeFromAddressPool(self, currency, address): |
183
|
|
|
"""Remove address from pool""" |
184
|
|
|
uri = f'{self.apibase}{currency}/address/{address}' |
185
|
|
|
params = {'currency': currency, 'address': address} |
186
|
|
|
avail_params = ['currency', 'address'] |
187
|
|
|
p = ParameterBuilder({}, {}, uri) |
188
|
|
|
p.verify_keys_and_values(avail_params, params) |
189
|
|
|
return self.APIConnect('DELETE', p) |
190
|
|
|
|
191
|
|
|
def listAddressPool(self, currency, **args): |
192
|
|
|
"""List address pool""" |
193
|
|
|
uri = f'{self.apibase}{currency}/address' |
194
|
|
|
params = args |
195
|
|
|
avail_params = ['usable', 'comment', 'page'] |
196
|
|
|
p = ParameterBuilder(avail_params, params, uri) |
197
|
|
|
return self.APIConnect('GET', p) |
198
|
|
|
|
199
|
|
|
def showOrderbook(self, order_type, trading_pair, **args): |
200
|
|
|
"""Search Orderbook for offers.""" |
201
|
|
|
uri = f'{self.apibase}{trading_pair}/orderbook' |
202
|
|
|
params = {'type': order_type} |
203
|
|
|
params.update(args) |
204
|
|
|
avail_params = ['type', 'trading_pair', 'amount_currency_to_trade', 'price', |
205
|
|
|
'order_requirements_fullfilled', |
206
|
|
|
'only_kyc_full', 'only_express_orders', 'payment_option', |
207
|
|
|
'sepa_option', 'only_same_bankgroup', 'only_same_bic', |
208
|
|
|
'seat_of_bank', 'page_size'] |
209
|
|
|
p = ParameterBuilder(avail_params, params, uri) |
210
|
|
|
return self.APIConnect('GET', p) |
211
|
|
|
|
212
|
|
|
def showOrderDetails(self, trading_pair, order_id): |
213
|
|
|
"""Show details for an offer.""" |
214
|
|
|
uri = f'{self.apibase}{trading_pair}/orders/public/details/{order_id}' |
215
|
|
|
params = {'trading_pair': trading_pair, 'order_id': order_id} |
216
|
|
|
avail_params = ['trading_pair', 'order_id'] |
217
|
|
|
p = ParameterBuilder({}, {}, uri) |
218
|
|
|
p.verify_keys_and_values(avail_params, params) |
219
|
|
|
return self.APIConnect('GET', p) |
220
|
|
|
|
221
|
|
|
def createOrder(self, order_type, trading_pair, max_amount_currency_to_trade, price, **args): |
222
|
|
|
"""Create a new Order.""" |
223
|
|
|
uri = f'{self.apibase}{trading_pair}/orders' |
224
|
|
|
# Build parameters |
225
|
|
|
params = {'type': order_type, |
226
|
|
|
'max_amount_currency_to_trade': max_amount_currency_to_trade, |
227
|
|
|
'price': price} |
228
|
|
|
params.update(args) |
229
|
|
|
avail_params = ['type', 'max_amount_currency_to_trade', 'price', |
230
|
|
|
'min_amount_currency_to_trade', 'end_datetime', |
231
|
|
|
'new_order_for_remaining_amount', 'trading_pair', |
232
|
|
|
'min_trust_level', 'only_kyc_full', 'payment_option', |
233
|
|
|
'sepa_option', 'seat_of_bank'] |
234
|
|
|
p = ParameterBuilder(avail_params, params, uri) |
235
|
|
|
p.verify_keys_and_values(avail_params, {'trading_pair': trading_pair}) |
236
|
|
|
return self.APIConnect('POST', p) |
237
|
|
|
|
238
|
|
|
def deleteOrder(self, order_id, trading_pair): |
239
|
|
|
"""Delete an Order.""" |
240
|
|
|
# Build parameters |
241
|
|
|
uri = f'{self.apibase}{trading_pair}/orders/{order_id}' |
242
|
|
|
avail_params = ['order_id', 'trading_pair'] |
243
|
|
|
params = { 'order_id': order_id, 'trading_pair': trading_pair} |
244
|
|
|
p = ParameterBuilder({}, {}, uri) |
245
|
|
|
p.verify_keys_and_values(avail_params, params) |
246
|
|
|
return self.APIConnect('DELETE', p) |
247
|
|
|
|
248
|
|
|
def showMyOrders(self, **args): |
249
|
|
|
"""Query and Filter own Orders.""" |
250
|
|
|
# Build parameters |
251
|
|
|
params = args |
252
|
|
|
avail_params = ['type', 'trading_pair', 'state', |
253
|
|
|
'date_start', 'date_end', 'page'] |
254
|
|
|
if params.get("trading_pair"): |
255
|
|
|
uri = f'{self.apibase}{params["trading_pair"]}/orders' |
256
|
|
|
del params["trading_pair"] |
257
|
|
|
else: |
258
|
|
|
uri = f'{self.apibase}orders' |
259
|
|
|
p = ParameterBuilder(avail_params, params, uri) |
260
|
|
|
return self.APIConnect('GET', p) |
261
|
|
|
|
262
|
|
|
def showMyOrderDetails(self, trading_pair, order_id): |
263
|
|
|
"""Details to an own Order.""" |
264
|
|
|
uri = f'{self.apibase}{trading_pair}/orders/{order_id}' |
265
|
|
|
p = ParameterBuilder({}, {}, uri) |
266
|
|
|
return self.APIConnect('GET', p) |
267
|
|
|
|
268
|
|
|
def executeTrade(self, trading_pair, order_id, order_type, amount): |
269
|
|
|
"""Buy/Sell on a specific Order.""" |
270
|
|
|
uri = f'{self.apibase}{trading_pair}/trades/{order_id}' |
271
|
|
|
params = { 'type': order_type, |
272
|
|
|
'amount_currency_to_trade': amount} |
273
|
|
|
avail_params = ['type', 'amount_currency_to_trade'] |
274
|
|
|
p = ParameterBuilder(avail_params, params, uri) |
275
|
|
|
return self.APIConnect('POST', p) |
276
|
|
|
|
277
|
|
|
def showMyTrades(self, **args): |
278
|
|
|
"""Query and Filter on past Trades.""" |
279
|
|
|
# Build parameters |
280
|
|
|
params = args |
281
|
|
|
avail_params = ['type', 'trading_pair', 'state', |
282
|
|
|
'only_trades_with_action_for_payment_or_transfer_required', |
283
|
|
|
'payment_method', 'date_start', 'date_end', 'page'] |
284
|
|
|
if params.get("trading_pair"): |
285
|
|
|
uri = f'{self.apibase}{params["trading_pair"]}/trades' |
286
|
|
|
del params["trading_pair"] |
287
|
|
|
else: |
288
|
|
|
uri = f'{self.apibase}trades' |
289
|
|
|
p = ParameterBuilder(avail_params, params, uri) |
290
|
|
|
return self.APIConnect('GET', p) |
291
|
|
|
|
292
|
|
|
def showMyTradeDetails(self, trading_pair, trade_id): |
293
|
|
|
"""Details to a specific Trade.""" |
294
|
|
|
params = {'trading_pair': trading_pair, 'trade_id': trade_id} |
295
|
|
|
avail_params = [ 'trading_pair', 'trade_id' ] |
296
|
|
|
uri = f'{self.apibase}{trading_pair}/trades/{trade_id}' |
297
|
|
|
p = ParameterBuilder({}, {}, uri) |
298
|
|
|
p.verify_keys_and_values(avail_params, params) |
299
|
|
|
return self.APIConnect('GET', p) |
300
|
|
|
|
301
|
|
|
def markCoinsAsTransferred(self, trading_pair, trade_id, amount_currency_to_trade_after_fee): |
302
|
|
|
"""Mark trade as transferred.""" |
303
|
|
|
params = {'amount_currency_to_trade_after_fee': amount_currency_to_trade_after_fee, |
304
|
|
|
'trading_pair': trading_pair, 'trade_id': trade_id} |
305
|
|
|
|
306
|
|
|
avail_params = [ 'trading_pair', 'trade_id', 'amount_currency_to_trade_after_fee' ] |
307
|
|
|
uri = f'{self.apibase}{trading_pair}/trades/{trade_id}/mark_coins_as_transferred' |
308
|
|
|
p = ParameterBuilder(avail_params, |
309
|
|
|
{'amount_currency_to_trade_after_fee': amount_currency_to_trade_after_fee}, uri) |
310
|
|
|
p.verify_keys_and_values(avail_params, params) |
311
|
|
|
return self.APIConnect('POST', p) |
312
|
|
|
|
313
|
|
|
def markTradeAsPaid(self, trading_pair, trade_id, volume_currency_to_pay_after_fee): |
314
|
|
|
"""Mark traded as paid.""" |
315
|
|
|
params = {'volume_currency_to_pay_after_fee': volume_currency_to_pay_after_fee, |
316
|
|
|
'trading_pair': trading_pair, 'trade_id': trade_id} |
317
|
|
|
|
318
|
|
|
avail_params = [ 'trading_pair', 'trade_id', 'volume_currency_to_pay_after_fee' ] |
319
|
|
|
uri = f'{self.apibase}{trading_pair}/trades/{trade_id}/mark_trade_as_paid' |
320
|
|
|
p = ParameterBuilder(avail_params, |
321
|
|
|
{'volume_currency_to_pay_after_fee': volume_currency_to_pay_after_fee}, uri) |
322
|
|
|
p.verify_keys_and_values(avail_params, params) |
323
|
|
|
return self.APIConnect('POST', p) |
324
|
|
|
|
325
|
|
|
def markCoinsAsReceived(self, trading_pair, trade_id, amount_currency_to_trade_after_fee, rating): |
326
|
|
|
"""Mark coins as received.""" |
327
|
|
|
params = {'amount_currency_to_trade_after_fee': amount_currency_to_trade_after_fee, |
328
|
|
|
'trading_pair': trading_pair, 'trade_id': trade_id, 'rating': rating} |
329
|
|
|
params_post = {'amount_currency_to_trade_after_fee': amount_currency_to_trade_after_fee, |
330
|
|
|
'rating': rating} |
331
|
|
|
avail_params = [ 'trading_pair', 'trade_id', 'amount_currency_to_trade_after_fee', 'rating' ] |
332
|
|
|
uri = f'{self.apibase}{trading_pair}/trades/{trade_id}/mark_coins_as_received' |
333
|
|
|
p = ParameterBuilder(avail_params, params_post, uri) |
334
|
|
|
p.verify_keys_and_values(avail_params, params) |
335
|
|
|
return self.APIConnect('POST', p) |
336
|
|
|
|
337
|
|
|
def markTradeAsPaymentReceived(self, trading_pair, trade_id, |
338
|
|
|
volume_currency_to_pay_after_fee, rating, |
339
|
|
|
is_paid_from_correct_bank_account): |
340
|
|
|
"""Mark coins as received.""" |
341
|
|
|
params = {'volume_currency_to_pay_after_fee': volume_currency_to_pay_after_fee, |
342
|
|
|
'trading_pair': trading_pair, 'trade_id': trade_id, 'rating': rating} |
343
|
|
|
params_post = {'volume_currency_to_pay_after_fee': volume_currency_to_pay_after_fee, |
344
|
|
|
'rating': rating, |
345
|
|
|
'is_paid_from_correct_bank_account': is_paid_from_correct_bank_account} |
346
|
|
|
avail_params = [ 'trading_pair', 'trade_id', 'volume_currency_to_pay_after_fee', |
347
|
|
|
'rating', 'is_paid_from_correct_bank_account' ] |
348
|
|
|
uri = f'{self.apibase}{trading_pair}/trades/{trade_id}/mark_trade_as_payment_received' |
349
|
|
|
p = ParameterBuilder(avail_params, params_post, uri) |
350
|
|
|
p.verify_keys_and_values(avail_params, params) |
351
|
|
|
return self.APIConnect('POST', p) |
352
|
|
|
|
353
|
|
|
def addTradeRating(self, trading_pair, trade_id, rating): |
354
|
|
|
"""Mark coins as received.""" |
355
|
|
|
params = {'trading_pair': trading_pair, 'trade_id': trade_id, 'rating': rating} |
356
|
|
|
params_post = {'rating': rating} |
357
|
|
|
avail_params = [ 'trading_pair', 'trade_id', 'rating' ] |
358
|
|
|
uri = f'{self.apibase}{trading_pair}/trades/{trade_id}/add_trade_rating' |
359
|
|
|
p = ParameterBuilder(avail_params, params_post, uri) |
360
|
|
|
p.verify_keys_and_values(avail_params, params) |
361
|
|
|
return self.APIConnect('POST', p) |
362
|
|
|
|
363
|
|
|
def showAccountInfo(self): |
364
|
|
|
"""Query on Account Infos.""" |
365
|
|
|
uri = f'{self.apibase}account' |
366
|
|
|
p = ParameterBuilder({}, {}, uri) |
367
|
|
|
return self.APIConnect('GET', p) |
368
|
|
|
|
369
|
|
|
def showOrderbookCompact(self, trading_pair): |
370
|
|
|
"""Bids and Asks in compact format.""" |
371
|
|
|
params = {'trading_pair': trading_pair} |
372
|
|
|
avail_params = ['trading_pair'] |
373
|
|
|
uri = f'{self.apibase}{trading_pair}/orderbook/compact' |
374
|
|
|
# Build parameters |
375
|
|
|
p = ParameterBuilder({}, {}, uri) |
376
|
|
|
p.verify_keys_and_values(avail_params, params) |
377
|
|
|
return self.APIConnect('GET', p) |
378
|
|
|
|
379
|
|
|
def showPublicTradeHistory(self, trading_pair, **args): |
380
|
|
|
"""All successful trades of the last 24 hours.""" |
381
|
|
|
params = { 'trading_pair': trading_pair } |
382
|
|
|
params.update(args) |
383
|
|
|
avail_params = ['trading_pair', 'since_tid'] |
384
|
|
|
uri = f'{self.apibase}{trading_pair}/trades/history' |
385
|
|
|
if params.get('since_tid'): |
386
|
|
|
del params["trading_pair"] |
387
|
|
|
p = ParameterBuilder(avail_params, params, uri) |
388
|
|
|
else: |
389
|
|
|
p = ParameterBuilder({}, {}, uri) |
390
|
|
|
p.verify_keys_and_values(avail_params, params) |
391
|
|
|
return self.APIConnect('GET', p) |
392
|
|
|
|
393
|
|
|
def showRates(self, trading_pair): |
394
|
|
|
"""Query of the average rate last 3 and 12 hours.""" |
395
|
|
|
uri = f'{self.apibase}{trading_pair}/rates' |
396
|
|
|
params = {'trading_pair': trading_pair} |
397
|
|
|
avail_params = ['trading_pair'] |
398
|
|
|
# Build parameters |
399
|
|
|
p = ParameterBuilder({}, {}, uri) |
400
|
|
|
p.verify_keys_and_values(avail_params, params) |
401
|
|
|
return self.APIConnect('GET', p) |
402
|
|
|
|
403
|
|
|
def showAccountLedger(self, currency, **args): |
404
|
|
|
"""Query on Account statement.""" |
405
|
|
|
params = {'currency': currency} |
406
|
|
|
params.update(args) |
407
|
|
|
uri = f'{self.apibase}{currency}/account/ledger' |
408
|
|
|
avail_params = ['currency', 'type', |
409
|
|
|
'datetime_start', 'datetime_end', 'page'] |
410
|
|
|
p = ParameterBuilder(avail_params, params, uri) |
411
|
|
|
del params['currency'] |
412
|
|
|
p = ParameterBuilder(avail_params, params, uri) |
413
|
|
|
return self.APIConnect('GET', p) |
414
|
|
|
|
415
|
|
|
def showPermissions(self): |
416
|
|
|
"""Show permissions that are allowed for used API key""" |
417
|
|
|
uri = f'{self.apibase}permissions' |
418
|
|
|
p = ParameterBuilder({}, {}, uri) |
419
|
|
|
return self.APIConnect('GET', p) |