ccxt 3.1.60__py2.py3-none-any.whl → 4.0.3__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
ccxt/buda.py DELETED
@@ -1,1063 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
- # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
-
6
- from ccxt.base.exchange import Exchange
7
- import hashlib
8
- from ccxt.base.types import OrderSide
9
- from typing import Optional
10
- from ccxt.base.errors import ExchangeError
11
- from ccxt.base.errors import PermissionDenied
12
- from ccxt.base.errors import ArgumentsRequired
13
- from ccxt.base.errors import NotSupported
14
- from ccxt.base.errors import AuthenticationError
15
- from ccxt.base.errors import AddressPending
16
- from ccxt.base.decimal_to_precision import TICK_SIZE
17
- from ccxt.base.precise import Precise
18
-
19
-
20
- class buda(Exchange):
21
-
22
- def describe(self):
23
- return self.deep_extend(super(buda, self).describe(), {
24
- 'id': 'buda',
25
- 'name': 'Buda',
26
- 'countries': ['AR', 'CL', 'CO', 'PE'],
27
- 'rateLimit': 1000,
28
- 'version': 'v2',
29
- 'has': {
30
- 'CORS': None,
31
- 'spot': True,
32
- 'margin': False,
33
- 'swap': False,
34
- 'future': False,
35
- 'option': False,
36
- 'addMargin': False,
37
- 'cancelOrder': True,
38
- 'createDepositAddress': True,
39
- 'createOrder': True,
40
- 'createReduceOnlyOrder': False,
41
- 'fetchBalance': True,
42
- 'fetchBorrowRate': False,
43
- 'fetchBorrowRateHistories': False,
44
- 'fetchBorrowRateHistory': False,
45
- 'fetchBorrowRates': False,
46
- 'fetchBorrowRatesPerSymbol': False,
47
- 'fetchClosedOrders': True,
48
- 'fetchCurrencies': True,
49
- 'fetchDepositAddress': True,
50
- 'fetchDeposits': True,
51
- 'fetchFundingHistory': False,
52
- 'fetchFundingRate': False,
53
- 'fetchFundingRateHistory': False,
54
- 'fetchFundingRates': False,
55
- 'fetchIndexOHLCV': False,
56
- 'fetchLeverage': False,
57
- 'fetchMarginMode': False,
58
- 'fetchMarkets': True,
59
- 'fetchMarkOHLCV': False,
60
- 'fetchMyTrades': False,
61
- 'fetchOHLCV': True,
62
- 'fetchOpenInterestHistory': False,
63
- 'fetchOpenOrders': True,
64
- 'fetchOrder': True,
65
- 'fetchOrderBook': True,
66
- 'fetchOrders': True,
67
- 'fetchPosition': False,
68
- 'fetchPositionMode': False,
69
- 'fetchPositions': False,
70
- 'fetchPositionsRisk': False,
71
- 'fetchPremiumIndexOHLCV': False,
72
- 'fetchTicker': True,
73
- 'fetchTrades': True,
74
- 'fetchTradingFee': False,
75
- 'fetchTradingFees': False,
76
- 'fetchTransactionFees': True,
77
- 'fetchTransfer': False,
78
- 'fetchTransfers': False,
79
- 'fetchWithdrawal': False,
80
- 'fetchWithdrawals': True,
81
- 'reduceMargin': False,
82
- 'setLeverage': False,
83
- 'setMarginMode': False,
84
- 'setPositionMode': False,
85
- 'transfer': False,
86
- 'withdraw': True,
87
- },
88
- 'urls': {
89
- 'logo': 'https://user-images.githubusercontent.com/1294454/47380619-8a029200-d706-11e8-91e0-8a391fe48de3.jpg',
90
- 'api': {
91
- 'rest': 'https://www.buda.com/api',
92
- },
93
- 'www': 'https://www.buda.com',
94
- 'doc': 'https://api.buda.com',
95
- 'fees': 'https://www.buda.com/comisiones',
96
- },
97
- 'status': {
98
- 'status': 'error',
99
- 'updated': None,
100
- 'eta': None,
101
- 'url': None,
102
- },
103
- 'api': {
104
- 'public': {
105
- 'get': [
106
- 'pairs',
107
- 'markets',
108
- 'currencies',
109
- 'markets/{market}',
110
- 'markets/{market}/ticker',
111
- 'markets/{market}/volume',
112
- 'markets/{market}/order_book',
113
- 'markets/{market}/trades',
114
- 'currencies/{currency}/fees/deposit',
115
- 'currencies/{currency}/fees/withdrawal',
116
- 'tv/history',
117
- ],
118
- 'post': [
119
- 'markets/{market}/quotations',
120
- ],
121
- },
122
- 'private': {
123
- 'get': [
124
- 'balances',
125
- 'balances/{currency}',
126
- 'currencies/{currency}/balances',
127
- 'orders',
128
- 'orders/{id}',
129
- 'markets/{market}/orders',
130
- 'deposits',
131
- 'currencies/{currency}/deposits',
132
- 'withdrawals',
133
- 'currencies/{currency}/withdrawals',
134
- 'currencies/{currency}/receive_addresses',
135
- 'currencies/{currency}/receive_addresses/{id}',
136
- ],
137
- 'post': [
138
- 'markets/{market}/orders',
139
- 'currencies/{currency}/deposits',
140
- 'currencies/{currency}/withdrawals',
141
- 'currencies/{currency}/simulated_withdrawals',
142
- 'currencies/{currency}/receive_addresses',
143
- ],
144
- 'put': [
145
- 'orders/{id}',
146
- ],
147
- },
148
- },
149
- 'timeframes': {
150
- '1m': '1',
151
- '5m': '5',
152
- '30m': '30',
153
- '1h': '60',
154
- '2h': '120',
155
- '1d': 'D',
156
- '1w': 'W',
157
- },
158
- 'fees': {
159
- 'trading': {
160
- 'tierBased': True,
161
- 'percentage': True,
162
- 'taker': 0.008, # 0.8%
163
- 'maker': 0.004, # 0.4%
164
- 'tiers': {
165
- 'taker': [
166
- [0, 0.008], # 0.8%
167
- [2000, 0.007], # 0.7%
168
- [20000, 0.006], # 0.6%
169
- [100000, 0.005], # 0.5%
170
- [500000, 0.004], # 0.4%
171
- [2500000, 0.003], # 0.3%
172
- [12500000, 0.002], # 0.2%
173
- ],
174
- 'maker': [
175
- [0, 0.004], # 0.4%
176
- [2000, 0.0035], # 0.35%
177
- [20000, 0.003], # 0.3%
178
- [100000, 0.0025], # 0.25%
179
- [500000, 0.002], # 0.2%
180
- [2500000, 0.0015], # 0.15%
181
- [12500000, 0.001], # 0.1%
182
- ],
183
- },
184
- },
185
- },
186
- 'precisionMode': TICK_SIZE,
187
- 'exceptions': {
188
- 'not_authorized': AuthenticationError, # {message: 'Invalid credentials', code: 'not_authorized'}
189
- 'forbidden': PermissionDenied, # {message: 'You dont have access to self resource', code: 'forbidden'}
190
- 'invalid_record': ExchangeError, # {message: 'Validation Failed', code: 'invalid_record', errors: []}
191
- 'not_found': ExchangeError, # {message: 'Not found', code: 'not_found'}
192
- 'parameter_missing': ExchangeError, # {message: 'Parameter missing', code: 'parameter_missing'}
193
- 'bad_parameter': ExchangeError, # {message: 'Bad Parameter format', code: 'bad_parameter'}
194
- },
195
- })
196
-
197
- def fetch_currency_info(self, currency, currencies=None):
198
- if not currencies:
199
- response = self.publicGetCurrencies()
200
- #
201
- # {
202
- # "currencies":[
203
- # {
204
- # "id":"BTC",
205
- # "symbol":"฿",
206
- # "managed":true,
207
- # "input_decimals":8,
208
- # "display_decimals":8,
209
- # "timezone":"UTC",
210
- # "deposit_minimum":["0.0","BTC"],
211
- # "withdrawal_minimum":["0.00001","BTC"],
212
- # "max_digits_for_decimals":6,
213
- # "crypto":true,
214
- # "address_explorer":"https://blockchair.com/bitcoin/address/",
215
- # "tx_explorer":"https://blockchair.com/bitcoin/transaction/",
216
- # "amount_to_micro_multiplier":1000000000000
217
- # }
218
- # ]
219
- # }
220
- #
221
- currencies = self.safe_value(response, 'currencies')
222
- for i in range(0, len(currencies)):
223
- currencyInfo = currencies[i]
224
- if currencyInfo['id'] == currency:
225
- return currencyInfo
226
- return None
227
-
228
- def fetch_markets(self, params={}):
229
- """
230
- retrieves data on all markets for buda
231
- :param dict params: extra parameters specific to the exchange api endpoint
232
- :returns [dict]: an array of objects representing market data
233
- """
234
- marketsResponse = self.publicGetMarkets(params)
235
- #
236
- # {
237
- # "markets": [
238
- # {
239
- # "id": "BTC-CLP",
240
- # "name": "btc-clp",
241
- # "base_currency": "BTC",
242
- # "quote_currency": "CLP",
243
- # "minimum_order_amount": [
244
- # "0.00002",
245
- # "BTC"
246
- # ],
247
- # "disabled": False,
248
- # "illiquid": False,
249
- # "rpo_disabled": null,
250
- # "taker_fee": "0.8",
251
- # "maker_fee": "0.4",
252
- # "max_orders_per_minute": 50,
253
- # "maker_discount_percentage": "0.0",
254
- # "taker_discount_percentage": "0.0"
255
- # },
256
- # ]
257
- # }
258
- #
259
- markets = self.safe_value(marketsResponse, 'markets', [])
260
- currenciesResponse = self.publicGetCurrencies()
261
- currencies = self.safe_value(currenciesResponse, 'currencies')
262
- result = []
263
- for i in range(0, len(markets)):
264
- market = markets[i]
265
- baseId = self.safe_string(market, 'base_currency')
266
- quoteId = self.safe_string(market, 'quote_currency')
267
- base = self.safe_currency_code(baseId)
268
- quote = self.safe_currency_code(quoteId)
269
- baseInfo = self.fetch_currency_info(baseId, currencies)
270
- quoteInfo = self.fetch_currency_info(quoteId, currencies)
271
- minimumOrderAmount = self.safe_value(market, 'minimum_order_amount', [])
272
- taker_fee = self.safe_string(market, 'taker_fee')
273
- maker_fee = self.safe_string(market, 'maker_fee')
274
- result.append({
275
- 'id': self.safe_string(market, 'id'),
276
- 'symbol': base + '/' + quote,
277
- 'base': base,
278
- 'quote': quote,
279
- 'settle': None,
280
- 'baseId': baseId,
281
- 'quoteId': quoteId,
282
- 'settleId': None,
283
- 'type': 'spot',
284
- 'spot': True,
285
- 'margin': False,
286
- 'swap': False,
287
- 'future': False,
288
- 'option': False,
289
- 'active': True,
290
- 'contract': False,
291
- 'linear': None,
292
- 'inverse': None,
293
- 'contractSize': None,
294
- 'expiry': None,
295
- 'expiryDatetime': None,
296
- 'strike': None,
297
- 'optionType': None,
298
- 'taker': self.parse_number(Precise.string_div(taker_fee, '1000')),
299
- 'maker': self.parse_number(Precise.string_div(maker_fee, '1000')),
300
- 'precision': {
301
- 'amount': self.parse_number(self.parse_precision(self.safe_string(baseInfo, 'input_decimals'))),
302
- 'price': self.parse_number(self.parse_precision(self.safe_string(quoteInfo, 'input_decimals'))),
303
- },
304
- 'limits': {
305
- 'leverage': {
306
- 'min': None,
307
- 'max': None,
308
- },
309
- 'amount': {
310
- 'min': self.safe_number(minimumOrderAmount, 0),
311
- 'max': None,
312
- },
313
- 'price': {
314
- 'min': None,
315
- 'max': None,
316
- },
317
- 'cost': {
318
- 'min': None,
319
- 'max': None,
320
- },
321
- },
322
- 'info': market,
323
- })
324
- return result
325
-
326
- def fetch_currencies(self, params={}):
327
- """
328
- fetches all available currencies on an exchange
329
- :param dict params: extra parameters specific to the buda api endpoint
330
- :returns dict: an associative dictionary of currencies
331
- """
332
- response = self.publicGetCurrencies()
333
- #
334
- # {
335
- # "currencies":[
336
- # {
337
- # "id":"BTC",
338
- # "symbol":"฿",
339
- # "managed":true,
340
- # "input_decimals":8,
341
- # "display_decimals":8,
342
- # "timezone":"UTC",
343
- # "deposit_minimum":["0.0","BTC"],
344
- # "withdrawal_minimum":["0.00001","BTC"],
345
- # "max_digits_for_decimals":6,
346
- # "crypto":true,
347
- # "address_explorer":"https://blockchair.com/bitcoin/address/",
348
- # "tx_explorer":"https://blockchair.com/bitcoin/transaction/",
349
- # "amount_to_micro_multiplier":1000000000000
350
- # }
351
- # ]
352
- # }
353
- #
354
- currencies = response['currencies']
355
- result = {}
356
- for i in range(0, len(currencies)):
357
- currency = currencies[i]
358
- managed = self.safe_value(currency, 'managed', False)
359
- if not managed:
360
- continue
361
- id = self.safe_string(currency, 'id')
362
- code = self.safe_currency_code(id)
363
- precision = self.parse_number(self.parse_precision(self.safe_string(currency, 'input_decimals')))
364
- depositMinimum = self.safe_value(currency, 'deposit_minimum', [])
365
- withdrawalMinimum = self.safe_value(currency, 'withdrawal_minimum', [])
366
- minDeposit = self.safe_number(depositMinimum, 0)
367
- minWithdraw = self.safe_number(withdrawalMinimum, 0)
368
- result[code] = {
369
- 'id': id,
370
- 'code': code,
371
- 'info': currency,
372
- 'name': None,
373
- 'active': True,
374
- 'deposit': None,
375
- 'withdraw': None,
376
- 'fee': None,
377
- 'precision': precision,
378
- 'limits': {
379
- 'amount': {
380
- 'min': precision,
381
- 'max': None,
382
- },
383
- 'deposit': {
384
- 'min': minDeposit,
385
- 'max': None,
386
- },
387
- 'withdraw': {
388
- 'min': minWithdraw,
389
- },
390
- },
391
- }
392
- return result
393
-
394
- def fetch_transaction_fees(self, codes=None, params={}):
395
- """
396
- fetch transaction fees
397
- :param [str]|None codes: list of unified currency codes
398
- :param dict params: extra parameters specific to the buda api endpoint
399
- :returns dict: a list of `fees structures <https://docs.ccxt.com/#/?id=fee-structure>`
400
- """
401
- # by default it will try load withdrawal fees of all currencies(with separate requests)
402
- # however if you define codes = ['ETH', 'BTC'] in args it will only load those
403
- self.load_markets()
404
- withdrawFees = {}
405
- depositFees = {}
406
- info = {}
407
- if codes is None:
408
- codes = list(self.currencies.keys())
409
- for i in range(0, len(codes)):
410
- code = codes[i]
411
- currency = self.currency(code)
412
- request = {'currency': currency['id']}
413
- withdrawResponse = self.publicGetCurrenciesCurrencyFeesWithdrawal(request)
414
- depositResponse = self.publicGetCurrenciesCurrencyFeesDeposit(request)
415
- withdrawFees[code] = self.parse_transaction_fee(withdrawResponse['fee'])
416
- depositFees[code] = self.parse_transaction_fee(depositResponse['fee'])
417
- info[code] = {
418
- 'withdraw': withdrawResponse,
419
- 'deposit': depositResponse,
420
- }
421
- return {
422
- 'withdraw': withdrawFees,
423
- 'deposit': depositFees,
424
- 'info': info,
425
- }
426
-
427
- def parse_transaction_fee(self, fee, type=None):
428
- if type is None:
429
- type = fee['name']
430
- if type == 'withdrawal':
431
- type = 'withdraw'
432
- return {
433
- 'type': type,
434
- 'currency': fee['base'][1],
435
- 'rate': fee['percent'],
436
- 'cost': float(fee['base'][0]),
437
- }
438
-
439
- def fetch_ticker(self, symbol: str, params={}):
440
- """
441
- fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
442
- :param str symbol: unified symbol of the market to fetch the ticker for
443
- :param dict params: extra parameters specific to the buda api endpoint
444
- :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
445
- """
446
- self.load_markets()
447
- market = self.market(symbol)
448
- request = {
449
- 'market': market['id'],
450
- }
451
- response = self.publicGetMarketsMarketTicker(self.extend(request, params))
452
- #
453
- # {
454
- # "ticker":{
455
- # "market_id":"ETH-BTC",
456
- # "last_price":["0.07300001","BTC"],
457
- # "min_ask":["0.07716895","BTC"],
458
- # "max_bid":["0.0754966","BTC"],
459
- # "volume":["0.168965697","ETH"],
460
- # "price_variation_24h":"-0.046",
461
- # "price_variation_7d":"-0.085"
462
- # }
463
- # }
464
- #
465
- ticker = self.safe_value(response, 'ticker')
466
- return self.parse_ticker(ticker, market)
467
-
468
- def parse_ticker(self, ticker, market=None):
469
- #
470
- # fetchTicker
471
- #
472
- # {
473
- # "market_id":"ETH-BTC",
474
- # "last_price":["0.07300001","BTC"],
475
- # "min_ask":["0.07716895","BTC"],
476
- # "max_bid":["0.0754966","BTC"],
477
- # "volume":["0.168965697","ETH"],
478
- # "price_variation_24h":"-0.046",
479
- # "price_variation_7d":"-0.085"
480
- # }
481
- #
482
- timestamp = self.milliseconds()
483
- marketId = self.safe_string(ticker, 'market_id')
484
- symbol = self.safe_symbol(marketId, market, '-')
485
- lastPrice = self.safe_value(ticker, 'last_price', [])
486
- last = self.safe_string(lastPrice, 0)
487
- percentage = self.safe_string(ticker, 'price_variation_24h')
488
- percentage = Precise.string_mul(percentage, '100')
489
- maxBid = self.safe_value(ticker, 'max_bid', [])
490
- minAsk = self.safe_value(ticker, 'min_ask', [])
491
- baseVolume = self.safe_value(ticker, 'volume', [])
492
- return self.safe_ticker({
493
- 'symbol': symbol,
494
- 'timestamp': timestamp,
495
- 'datetime': self.iso8601(timestamp),
496
- 'high': None,
497
- 'low': None,
498
- 'bid': self.safe_string(maxBid, 0),
499
- 'bidVolume': None,
500
- 'ask': self.safe_string(minAsk, 0),
501
- 'askVolume': None,
502
- 'vwap': None,
503
- 'open': None,
504
- 'close': last,
505
- 'last': last,
506
- 'previousClose': None,
507
- 'change': None,
508
- 'percentage': percentage,
509
- 'average': None,
510
- 'baseVolume': self.safe_string(baseVolume, 0),
511
- 'quoteVolume': None,
512
- 'info': ticker,
513
- }, market)
514
-
515
- def fetch_trades(self, symbol: str, since: Optional[int] = None, limit: Optional[int] = None, params={}):
516
- """
517
- get the list of most recent trades for a particular symbol
518
- :param str symbol: unified symbol of the market to fetch trades for
519
- :param int|None since: timestamp in ms of the earliest trade to fetch
520
- :param int|None limit: the maximum amount of trades to fetch
521
- :param dict params: extra parameters specific to the buda api endpoint
522
- :returns [dict]: a list of `trade structures <https://docs.ccxt.com/en/latest/manual.html?#public-trades>`
523
- """
524
- self.load_markets()
525
- market = self.market(symbol)
526
- request = {
527
- 'market': market['id'],
528
- }
529
- # the since argument works backwards – returns trades up to the specified timestamp
530
- # therefore not implemented here
531
- # the method is still available for users to be able to traverse backwards in time
532
- # by using the timestamp from the first received trade upon each iteration
533
- if limit is not None:
534
- request['limit'] = limit # 50 max
535
- response = self.publicGetMarketsMarketTrades(self.extend(request, params))
536
- #
537
- # {trades: { market_id: "ETH-BTC",
538
- # timestamp: null,
539
- # last_timestamp: "1536901277302",
540
- # entries: [["1540077456791", "0.0063767", "0.03", "sell", 479842],
541
- # ["1539916642772", "0.01888263", "0.03019563", "sell", 479438],
542
- # ["1539834081787", "0.023718648", "0.031001", "sell", 479069],
543
- # ...]
544
- #
545
- return self.parse_trades(response['trades']['entries'], market, since, limit)
546
-
547
- def parse_trade(self, trade, market=None):
548
- #
549
- # fetchTrades(public)
550
- # ["1540077456791", "0.0063767", "0.03", "sell", 479842]
551
- #
552
- timestamp = None
553
- side = None
554
- type = None
555
- priceString = None
556
- amountString = None
557
- id = None
558
- order = None
559
- fee = None
560
- symbol = None
561
- if market:
562
- symbol = market['symbol']
563
- if isinstance(trade, list):
564
- timestamp = self.safe_integer(trade, 0)
565
- priceString = self.safe_string(trade, 1)
566
- amountString = self.safe_string(trade, 2)
567
- side = self.safe_string(trade, 3)
568
- id = self.safe_string(trade, 4)
569
- return self.safe_trade({
570
- 'id': id,
571
- 'order': order,
572
- 'info': trade,
573
- 'timestamp': timestamp,
574
- 'datetime': self.iso8601(timestamp),
575
- 'symbol': symbol,
576
- 'type': type,
577
- 'side': side,
578
- 'takerOrMaker': None,
579
- 'price': priceString,
580
- 'amount': amountString,
581
- 'cost': None,
582
- 'fee': fee,
583
- }, market)
584
-
585
- def fetch_order_book(self, symbol: str, limit: Optional[int] = None, params={}):
586
- """
587
- fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
588
- :param str symbol: unified symbol of the market to fetch the order book for
589
- :param int|None limit: the maximum amount of order book entries to return
590
- :param dict params: extra parameters specific to the buda api endpoint
591
- :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
592
- """
593
- self.load_markets()
594
- market = self.market(symbol)
595
- request = {
596
- 'market': market['id'],
597
- }
598
- response = self.publicGetMarketsMarketOrderBook(self.extend(request, params))
599
- orderbook = self.safe_value(response, 'order_book')
600
- return self.parse_order_book(orderbook, market['symbol'])
601
-
602
- def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Optional[int] = None, limit: Optional[int] = None, params={}):
603
- """
604
- fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
605
- :param str symbol: unified symbol of the market to fetch OHLCV data for
606
- :param str timeframe: the length of time each candle represents
607
- :param int|None since: timestamp in ms of the earliest candle to fetch
608
- :param int|None limit: the maximum amount of candles to fetch
609
- :param dict params: extra parameters specific to the buda api endpoint
610
- :returns [[int]]: A list of candles ordered, open, high, low, close, volume
611
- """
612
- self.load_markets()
613
- market = self.market(symbol)
614
- if since is None:
615
- since = self.milliseconds() - 86400000
616
- request = {
617
- 'symbol': market['id'],
618
- 'resolution': self.safe_string(self.timeframes, timeframe, timeframe),
619
- 'from': since / 1000,
620
- 'to': self.seconds(),
621
- }
622
- response = self.publicGetTvHistory(self.extend(request, params))
623
- return self.parse_trading_view_ohlcv(response, market, timeframe, since, limit)
624
-
625
- def parse_balance(self, response):
626
- result = {'info': response}
627
- balances = self.safe_value(response, 'balances', [])
628
- for i in range(0, len(balances)):
629
- balance = balances[i]
630
- currencyId = self.safe_string(balance, 'id')
631
- code = self.safe_currency_code(currencyId)
632
- account = self.account()
633
- account['free'] = self.safe_string(balance['available_amount'], 0)
634
- account['total'] = self.safe_string(balance['amount'], 0)
635
- result[code] = account
636
- return self.safe_balance(result)
637
-
638
- def fetch_balance(self, params={}):
639
- """
640
- query for balance and get the amount of funds available for trading or funds locked in orders
641
- :param dict params: extra parameters specific to the buda api endpoint
642
- :returns dict: a `balance structure <https://docs.ccxt.com/en/latest/manual.html?#balance-structure>`
643
- """
644
- self.load_markets()
645
- response = self.privateGetBalances(params)
646
- return self.parse_balance(response)
647
-
648
- def fetch_order(self, id: str, symbol: Optional[str] = None, params={}):
649
- """
650
- fetches information on an order made by the user
651
- :param str|None symbol: not used by buda fetchOrder
652
- :param dict params: extra parameters specific to the buda api endpoint
653
- :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
654
- """
655
- self.load_markets()
656
- request = {
657
- 'id': int(id),
658
- }
659
- response = self.privateGetOrdersId(self.extend(request, params))
660
- order = self.safe_value(response, 'order')
661
- return self.parse_order(order)
662
-
663
- def fetch_orders(self, symbol: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
664
- """
665
- fetches information on multiple orders made by the user
666
- :param str|None symbol: unified market symbol of the market orders were made in
667
- :param int|None since: the earliest time in ms to fetch orders for
668
- :param int|None limit: the maximum number of orde structures to retrieve
669
- :param dict params: extra parameters specific to the buda api endpoint
670
- :returns [dict]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
671
- """
672
- self.load_markets()
673
- market = None
674
- if symbol is not None:
675
- market = self.market(symbol)
676
- request = {
677
- 'market': market['id'],
678
- 'per': limit,
679
- }
680
- response = self.privateGetMarketsMarketOrders(self.extend(request, params))
681
- orders = self.safe_value(response, 'orders')
682
- return self.parse_orders(orders, market, since, limit)
683
-
684
- def fetch_open_orders(self, symbol: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
685
- """
686
- fetch all unfilled currently open orders
687
- :param str|None symbol: unified market symbol
688
- :param int|None since: the earliest time in ms to fetch open orders for
689
- :param int|None limit: the maximum number of open orders structures to retrieve
690
- :param dict params: extra parameters specific to the buda api endpoint
691
- :returns [dict]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
692
- """
693
- request = {
694
- 'state': 'pending',
695
- }
696
- return self.fetch_orders(symbol, since, limit, self.extend(request, params))
697
-
698
- def fetch_closed_orders(self, symbol: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
699
- """
700
- fetches information on multiple closed orders made by the user
701
- :param str|None symbol: unified market symbol of the market orders were made in
702
- :param int|None since: the earliest time in ms to fetch orders for
703
- :param int|None limit: the maximum number of orde structures to retrieve
704
- :param dict params: extra parameters specific to the buda api endpoint
705
- :returns [dict]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
706
- """
707
- request = {
708
- 'state': 'traded',
709
- }
710
- return self.fetch_orders(symbol, since, limit, self.extend(request, params))
711
-
712
- def create_order(self, symbol: str, type, side: OrderSide, amount, price=None, params={}):
713
- """
714
- create a trade order
715
- :param str symbol: unified symbol of the market to create an order in
716
- :param str type: 'market' or 'limit'
717
- :param str side: 'buy' or 'sell'
718
- :param float amount: how much of currency you want to trade in units of base currency
719
- :param float|None price: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
720
- :param dict params: extra parameters specific to the buda api endpoint
721
- :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
722
- """
723
- self.load_markets()
724
- requestSide = 'Bid' if (side == 'buy') else 'Ask'
725
- market = self.market(symbol)
726
- request = {
727
- 'market': market['id'],
728
- 'price_type': type,
729
- 'type': requestSide,
730
- 'amount': self.amount_to_precision(symbol, amount),
731
- }
732
- if type == 'limit':
733
- request['limit'] = self.price_to_precision(symbol, price)
734
- response = self.privatePostMarketsMarketOrders(self.extend(request, params))
735
- order = self.safe_value(response, 'order')
736
- return self.parse_order(order)
737
-
738
- def cancel_order(self, id: str, symbol: Optional[str] = None, params={}):
739
- """
740
- cancels an open order
741
- :param str id: order id
742
- :param str|None symbol: not used by buda cancelOrder()
743
- :param dict params: extra parameters specific to the buda api endpoint
744
- :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
745
- """
746
- self.load_markets()
747
- request = {
748
- 'id': int(id),
749
- 'state': 'canceling',
750
- }
751
- response = self.privatePutOrdersId(self.extend(request, params))
752
- order = self.safe_value(response, 'order')
753
- return self.parse_order(order)
754
-
755
- def parse_order_status(self, status):
756
- statuses = {
757
- 'traded': 'closed',
758
- 'received': 'open',
759
- 'canceling': 'canceled',
760
- }
761
- return self.safe_string(statuses, status, status)
762
-
763
- def parse_order(self, order, market=None):
764
- #
765
- # {
766
- # 'id': 63679183,
767
- # 'uuid': 'f9697bee-627e-4175-983f-0d5a41963fec',
768
- # 'market_id': 'ETH-CLP',
769
- # 'account_id': 51590,
770
- # 'type': 'Ask',
771
- # 'state': 'received',
772
- # 'created_at': '2021-01-04T08:29:52.730Z',
773
- # 'fee_currency': 'CLP',
774
- # 'price_type': 'limit',
775
- # 'source': None,
776
- # 'limit': ['741000.0', 'CLP'],
777
- # 'amount': ['0.001', 'ETH'],
778
- # 'original_amount': ['0.001', 'ETH'],
779
- # 'traded_amount': ['0.0', 'ETH'],
780
- # 'total_exchanged': ['0.0', 'CLP'],
781
- # 'paid_fee': ['0.0', 'CLP']
782
- # }
783
- #
784
- id = self.safe_string(order, 'id')
785
- timestamp = self.parse8601(self.safe_string(order, 'created_at'))
786
- datetime = self.iso8601(timestamp)
787
- marketId = self.safe_string(order, 'market_id')
788
- symbol = self.safe_symbol(marketId, market, '-')
789
- type = self.safe_string(order, 'price_type')
790
- side = self.safe_string_lower(order, 'type')
791
- status = self.parse_order_status(self.safe_string(order, 'state'))
792
- originalAmount = self.safe_value(order, 'original_amount', [])
793
- amount = self.safe_string(originalAmount, 0)
794
- remainingAmount = self.safe_value(order, 'amount', [])
795
- remaining = self.safe_string(remainingAmount, 0)
796
- tradedAmount = self.safe_value(order, 'traded_amount', [])
797
- filled = self.safe_string(tradedAmount, 0)
798
- totalExchanged = self.safe_value(order, 'total_exchanged', [])
799
- cost = self.safe_string(totalExchanged, 0)
800
- limitPrice = self.safe_value(order, 'limit', [])
801
- price = self.safe_string(limitPrice, 0)
802
- if price is None:
803
- if limitPrice is not None:
804
- price = limitPrice
805
- paidFee = self.safe_value(order, 'paid_fee', [])
806
- feeCost = self.safe_string(paidFee, 0)
807
- fee = None
808
- if feeCost is not None:
809
- feeCurrencyId = self.safe_string(paidFee, 1)
810
- feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
811
- fee = {
812
- 'cost': feeCost,
813
- 'code': feeCurrencyCode, # kept here for backward-compatibility, but will be removed soon
814
- 'currency': feeCurrencyCode,
815
- }
816
- return self.safe_order({
817
- 'info': order,
818
- 'id': id,
819
- 'clientOrderId': None,
820
- 'datetime': datetime,
821
- 'timestamp': timestamp,
822
- 'lastTradeTimestamp': None,
823
- 'status': status,
824
- 'symbol': symbol,
825
- 'type': type,
826
- 'timeInForce': None,
827
- 'postOnly': None,
828
- 'side': side,
829
- 'price': price,
830
- 'stopPrice': None,
831
- 'triggerPrice': None,
832
- 'average': None,
833
- 'cost': cost,
834
- 'amount': amount,
835
- 'filled': filled,
836
- 'remaining': remaining,
837
- 'trades': None,
838
- 'fee': fee,
839
- }, market)
840
-
841
- def is_fiat(self, code):
842
- fiats = {
843
- 'ARS': True,
844
- 'CLP': True,
845
- 'COP': True,
846
- 'PEN': True,
847
- }
848
- return self.safe_value(fiats, code, False)
849
-
850
- def fetch_deposit_address(self, code: str, params={}):
851
- """
852
- fetch the deposit address for a currency associated with self account
853
- :param str code: unified currency code
854
- :param dict params: extra parameters specific to the buda api endpoint
855
- :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
856
- """
857
- self.load_markets()
858
- currency = self.currency(code)
859
- if self.is_fiat(code):
860
- raise NotSupported(self.id + ' fetchDepositAddress() for fiat ' + code + ' is not supported')
861
- request = {
862
- 'currency': currency['id'],
863
- }
864
- response = self.privateGetCurrenciesCurrencyReceiveAddresses(self.extend(request, params))
865
- receiveAddresses = self.safe_value(response, 'receive_addresses')
866
- addressPool = []
867
- for i in range(1, len(receiveAddresses)):
868
- receiveAddress = receiveAddresses[i]
869
- if receiveAddress['ready']:
870
- addressInner = receiveAddress['address']
871
- self.check_address(addressInner)
872
- addressPool.append(addressInner)
873
- addressPoolLength = len(addressPool)
874
- if addressPoolLength < 1:
875
- raise AddressPending(self.id + ': there are no addresses ready for receiving ' + code + ', retry again later)')
876
- address = addressPool[0]
877
- return {
878
- 'currency': code,
879
- 'address': address,
880
- 'tag': None,
881
- 'network': None,
882
- 'info': receiveAddresses,
883
- }
884
-
885
- def create_deposit_address(self, code: str, params={}):
886
- """
887
- create a currency deposit address
888
- :param str code: unified currency code of the currency for the deposit address
889
- :param dict params: extra parameters specific to the buda api endpoint
890
- :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
891
- """
892
- self.load_markets()
893
- currency = self.currency(code)
894
- if self.is_fiat(code):
895
- raise NotSupported(self.id + ' createDepositAddress() of fiat for ' + code + ' is not supported')
896
- request = {
897
- 'currency': currency['id'],
898
- }
899
- response = self.privatePostCurrenciesCurrencyReceiveAddresses(self.extend(request, params))
900
- address = self.safe_string(response['receive_address'], 'address') # the creation is async and returns a null address, returns only the id
901
- return {
902
- 'currency': code,
903
- 'address': address,
904
- 'tag': None,
905
- 'info': response,
906
- }
907
-
908
- def parse_transaction_status(self, status):
909
- statuses = {
910
- 'rejected': 'failed',
911
- 'confirmed': 'ok',
912
- 'aNoneed': 'canceled',
913
- 'retained': 'canceled',
914
- 'pending_confirmation': 'pending',
915
- }
916
- return self.safe_string(statuses, status, status)
917
-
918
- def parse_transaction(self, transaction, currency=None):
919
- id = self.safe_string(transaction, 'id')
920
- timestamp = self.parse8601(self.safe_string(transaction, 'created_at'))
921
- currencyId = self.safe_string(transaction, 'currency')
922
- code = self.safe_currency_code(currencyId, currency)
923
- amount = float(transaction['amount'][0])
924
- fee = float(transaction['fee'][0])
925
- feeCurrency = transaction['fee'][1]
926
- status = self.parse_transaction_status(self.safe_string(transaction, 'state'))
927
- type = 'deposit' if ('deposit_data' in transaction) else 'withdrawal'
928
- data = self.safe_value(transaction, type + '_data', {})
929
- address = self.safe_value(data, 'target_address')
930
- txid = self.safe_string(data, 'tx_hash')
931
- updated = self.parse8601(self.safe_string(data, 'updated_at'))
932
- return {
933
- 'info': transaction,
934
- 'id': id,
935
- 'txid': txid,
936
- 'timestamp': timestamp,
937
- 'datetime': self.iso8601(timestamp),
938
- 'network': None,
939
- 'address': address,
940
- 'addressTo': None,
941
- 'addressFrom': None,
942
- 'tag': None,
943
- 'tagTo': None,
944
- 'tagFrom': None,
945
- 'type': type,
946
- 'amount': amount,
947
- 'currency': code,
948
- 'status': status,
949
- 'updated': updated,
950
- 'fee': {
951
- 'cost': fee,
952
- 'rate': feeCurrency,
953
- },
954
- }
955
-
956
- def fetch_deposits(self, code: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
957
- """
958
- fetch all deposits made to an account
959
- :param str code: unified currency code
960
- :param int|None since: the earliest time in ms to fetch deposits for
961
- :param int|None limit: the maximum number of deposits structures to retrieve
962
- :param dict params: extra parameters specific to the buda api endpoint
963
- :returns [dict]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
964
- """
965
- self.load_markets()
966
- if code is None:
967
- raise ArgumentsRequired(self.id + ' fetchDeposits() requires a currency code argument')
968
- currency = self.currency(code)
969
- request = {
970
- 'currency': currency['id'],
971
- 'per': limit,
972
- }
973
- response = self.privateGetCurrenciesCurrencyDeposits(self.extend(request, params))
974
- deposits = self.safe_value(response, 'deposits')
975
- return self.parse_transactions(deposits, currency, since, limit)
976
-
977
- def fetch_withdrawals(self, code: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
978
- """
979
- fetch all withdrawals made from an account
980
- :param str code: unified currency code
981
- :param int|None since: the earliest time in ms to fetch withdrawals for
982
- :param int|None limit: the maximum number of withdrawals structures to retrieve
983
- :param dict params: extra parameters specific to the buda api endpoint
984
- :returns [dict]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
985
- """
986
- self.load_markets()
987
- if code is None:
988
- raise ArgumentsRequired(self.id + ' fetchWithdrawals() requires a currency code argument')
989
- currency = self.currency(code)
990
- request = {
991
- 'currency': currency['id'],
992
- 'per': limit,
993
- }
994
- response = self.privateGetCurrenciesCurrencyWithdrawals(self.extend(request, params))
995
- withdrawals = self.safe_value(response, 'withdrawals')
996
- return self.parse_transactions(withdrawals, currency, since, limit)
997
-
998
- def withdraw(self, code: str, amount, address, tag=None, params={}):
999
- """
1000
- make a withdrawal
1001
- :param str code: unified currency code
1002
- :param float amount: the amount to withdraw
1003
- :param str address: the address to withdraw to
1004
- :param str|None tag:
1005
- :param dict params: extra parameters specific to the buda api endpoint
1006
- :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
1007
- """
1008
- tag, params = self.handle_withdraw_tag_and_params(tag, params)
1009
- self.check_address(address)
1010
- self.load_markets()
1011
- currency = self.currency(code)
1012
- request = {
1013
- 'currency': currency['id'],
1014
- 'amount': amount,
1015
- 'withdrawal_data': {
1016
- 'target_address': address,
1017
- },
1018
- }
1019
- response = self.privatePostCurrenciesCurrencyWithdrawals(self.extend(request, params))
1020
- withdrawal = self.safe_value(response, 'withdrawal')
1021
- return self.parse_transaction(withdrawal)
1022
-
1023
- def nonce(self):
1024
- return self.microseconds()
1025
-
1026
- def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
1027
- request = self.implode_params(path, params)
1028
- query = self.omit(params, self.extract_params(path))
1029
- if query:
1030
- if method == 'GET':
1031
- request += '?' + self.urlencode(query)
1032
- else:
1033
- body = self.json(query)
1034
- url = self.urls['api']['rest'] + '/' + self.version + '/' + request
1035
- if api == 'private':
1036
- self.check_required_credentials()
1037
- nonce = str(self.nonce())
1038
- components = [method, '/api/' + self.version + '/' + request]
1039
- if body:
1040
- base64Body = self.string_to_base64(body)
1041
- components.append(base64Body)
1042
- components.append(nonce)
1043
- message = ' '.join(components)
1044
- signature = self.hmac(self.encode(message), self.encode(self.secret), hashlib.sha384)
1045
- headers = {
1046
- 'X-SBTC-APIKEY': self.apiKey,
1047
- 'X-SBTC-SIGNATURE': signature,
1048
- 'X-SBTC-NONCE': nonce,
1049
- 'Content-Type': 'application/json',
1050
- }
1051
- return {'url': url, 'method': method, 'body': body, 'headers': headers}
1052
-
1053
- def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
1054
- if response is None:
1055
- return None # fallback to default error handler
1056
- if code >= 400:
1057
- errorCode = self.safe_string(response, 'code')
1058
- message = self.safe_string(response, 'message', body)
1059
- feedback = self.id + ' ' + message
1060
- if errorCode is not None:
1061
- self.throw_exactly_matched_exception(self.exceptions, errorCode, feedback)
1062
- raise ExchangeError(feedback)
1063
- return None