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/stex.py DELETED
@@ -1,2508 +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
- from ccxt.abstract.stex import ImplicitAPI
8
- from ccxt.base.types import OrderSide
9
- from typing import Optional
10
- from typing import List
11
- from ccxt.base.errors import ExchangeError
12
- from ccxt.base.errors import PermissionDenied
13
- from ccxt.base.errors import AccountSuspended
14
- from ccxt.base.errors import ArgumentsRequired
15
- from ccxt.base.errors import BadRequest
16
- from ccxt.base.errors import BadSymbol
17
- from ccxt.base.errors import InsufficientFunds
18
- from ccxt.base.errors import InvalidOrder
19
- from ccxt.base.errors import OrderNotFound
20
- from ccxt.base.errors import DDoSProtection
21
- from ccxt.base.errors import AuthenticationError
22
- from ccxt.base.decimal_to_precision import TICK_SIZE
23
- from ccxt.base.precise import Precise
24
-
25
-
26
- class stex(Exchange, ImplicitAPI):
27
-
28
- def describe(self):
29
- return self.deep_extend(super(stex, self).describe(), {
30
- 'id': 'stex',
31
- 'name': 'STEX', # formerly known.exchange
32
- 'countries': ['EE'], # Estonia
33
- 'rateLimit': 1000 / 3, # https://help.stex.com/en/articles/2815043-api-3-rate-limits
34
- 'certified': False,
35
- # new metainfo interface
36
- 'has': {
37
- 'CORS': None,
38
- 'spot': True,
39
- 'margin': False,
40
- 'swap': False,
41
- 'future': False,
42
- 'option': False,
43
- 'addMargin': False,
44
- 'cancelAllOrders': True,
45
- 'cancelOrder': True,
46
- 'createDepositAddress': True,
47
- 'createMarketOrder': False,
48
- 'createOrder': True,
49
- 'createReduceOnlyOrder': False,
50
- 'fetchBalance': True,
51
- 'fetchBorrowRate': False,
52
- 'fetchBorrowRateHistories': False,
53
- 'fetchBorrowRateHistory': False,
54
- 'fetchBorrowRates': False,
55
- 'fetchBorrowRatesPerSymbol': False,
56
- 'fetchClosedOrder': True,
57
- 'fetchCurrencies': True,
58
- 'fetchDeposit': True,
59
- 'fetchDepositAddress': True,
60
- 'fetchDeposits': True,
61
- 'fetchDepositWithdrawFee': 'emulated',
62
- 'fetchDepositWithdrawFees': True,
63
- 'fetchFundingHistory': False,
64
- 'fetchFundingRate': False,
65
- 'fetchFundingRateHistory': False,
66
- 'fetchFundingRates': False,
67
- 'fetchIndexOHLCV': False,
68
- 'fetchLeverage': False,
69
- 'fetchLeverageTiers': False,
70
- 'fetchMarginMode': False,
71
- 'fetchMarkets': True,
72
- 'fetchMarkOHLCV': False,
73
- 'fetchMyTrades': True,
74
- 'fetchOHLCV': True,
75
- 'fetchOpenInterestHistory': False,
76
- 'fetchOpenOrders': True,
77
- 'fetchOrder': True,
78
- 'fetchOrderBook': True,
79
- 'fetchOrderTrades': True,
80
- 'fetchPosition': False,
81
- 'fetchPositionMode': False,
82
- 'fetchPositions': False,
83
- 'fetchPositionsRisk': False,
84
- 'fetchPremiumIndexOHLCV': False,
85
- 'fetchTicker': True,
86
- 'fetchTickers': True,
87
- 'fetchTime': True,
88
- 'fetchTrades': True,
89
- 'fetchTradingFee': True,
90
- 'fetchTradingFees': False,
91
- 'fetchTransactionFees': True,
92
- 'fetchWithdrawal': True,
93
- 'fetchWithdrawals': True,
94
- 'reduceMargin': False,
95
- 'setLeverage': False,
96
- 'setMarginMode': False,
97
- 'setPositionMode': False,
98
- 'transfer': True,
99
- 'withdraw': True,
100
- },
101
- 'version': 'v3',
102
- 'urls': {
103
- 'logo': 'https://user-images.githubusercontent.com/1294454/69680782-03fd0b80-10bd-11ea-909e-7f603500e9cc.jpg',
104
- 'api': {
105
- 'rest': 'https://api3.stex.com',
106
- },
107
- 'www': 'https://www.stex.com',
108
- 'doc': [
109
- 'https://apidocs.stex.com/',
110
- 'https://help.stex.com/en/collections/1593608-api-v3-documentation',
111
- ],
112
- 'fees': 'https://app.stex.com/en/pairs-specification',
113
- 'referral': 'https://app.stex.com?ref=36416021',
114
- },
115
- 'requiredCredentials': {
116
- 'apiKey': False,
117
- 'secret': False,
118
- 'token': True,
119
- },
120
- 'timeframes': {
121
- '1m': '1',
122
- '5m': '5',
123
- '30m': '30',
124
- '1h': '60',
125
- '4h': '240',
126
- '12h': '720',
127
- '1d': '1D', # default
128
- },
129
- 'api': {
130
- 'public': {
131
- 'get': {
132
- 'currencies': 1, # Available Currencies
133
- 'currencies/{currencyId}': 1, # Get currency info
134
- 'markets': 1, # Available markets
135
- 'pairs-groups': 1, # Available currency pairs groups(as displayed at stex trading page)
136
- 'currency_pairs/list/{code}': 1, # Available currency pairs
137
- 'currency_pairs/group/{currencyPairGroupId}': 1, # Available currency pairs for a given group
138
- 'currency_pairs/{currencyPairId}': 1, # Get currency pair information
139
- 'ticker': 1, # Tickers list for all currency pairs
140
- 'ticker/{currencyPairId}': 1, # Ticker for currency pair
141
- 'trades/{currencyPairId}': 1, # Trades for given currency pair
142
- 'orderbook/{currencyPairId}': 1, # Orderbook for given currency pair
143
- 'chart/{currencyPairId}/{candlesType}': 1, # A list of candles for given currency pair
144
- 'deposit-statuses': 1, # Available Deposit Statuses
145
- 'deposit-statuses/{statusId}': 1, # Get deposit status info
146
- 'withdrawal-statuses': 1, # Available Withdrawal Statuses
147
- 'withdrawal-statuses/{statusId}': 1, # Get status info
148
- 'ping': 1, # Test API is working and get server time
149
- 'mobile-versions': 1, # Shows the official mobile applications data
150
- 'twitter': 1, # Get the last 20 posts(stex.com) on Twitter
151
- },
152
- },
153
- 'trading': {
154
- 'get': {
155
- 'fees/{currencyPairId}': 1, # Returns the user's fees for a given currency pair
156
- 'orders': 12, # List your currently open orders
157
- 'orders/{currencyPairId}': 6, # List your currently open orders for given currency pair
158
- 'order/{orderId}': 12, # Get a single order
159
- },
160
- 'post': {
161
- 'orders/{currencyPairId}': 1.5, # Create new order and put it to the orders processing queue
162
- 'orders/bulk/{currencyPairId}': 12, # Create new orders in a bulk and put it to the orders processing queue
163
- },
164
- 'delete': {
165
- 'orders': 30, # Delete all active orders
166
- 'orders/{currencyPairId}': 12, # Delete active orders for given currency pair
167
- 'order/{orderId}': 1.5, # Cancel order
168
- },
169
- },
170
- 'reports': {
171
- 'get': {
172
- 'currencies': 12, # Get a list of currencies user had any activity in
173
- 'currency_pairs': 12, # Gets the list of currency pairs the user had orders in for all the time
174
- 'orders': 12, # Get past orders
175
- 'orders/{orderId}': 12, # Get specified order details
176
- 'trades/{currencyPairId}': 12, # Get a list of user trades according to request parameters
177
- 'background/{listMode}': 12, # Get reports list for category
178
- 'background/{id}': 12, # Get some report info
179
- 'background/download/{id}': 12, # Get file by id
180
- },
181
- 'post': {
182
- 'background/create': 12, # Create new report
183
- },
184
- 'delete': {
185
- 'background/{id}': 12, # Remove report by id
186
- },
187
- },
188
- 'profile': {
189
- 'get': {
190
- 'info': 3, # Account information
191
- 'wallets': 3, # Get a list of user wallets
192
- 'wallets/{walletId}': 3, # Single wallet information
193
- 'wallets/address/{walletId}': 3, # Get deposit address for given wallet
194
- 'deposits': 3, # Get a list of deposits made by user
195
- 'deposits/{id}': 3, # Get deposit by id
196
- 'rewards': 3, # Get a list of rewards obtained by user(e.g. in trading competitions)
197
- 'rewards/{id}': 3, # Get reward by id
198
- 'addressbook': 3, # Get a list of user address book items
199
- 'addressbook/{itemId}': 3, # Single address book item
200
- 'withdrawals': 3, # Get a list of withdrawals made by user
201
- 'withdrawals/{id}': 3, # Get withdrawal by id
202
- 'notifications': 3, # Get notifications
203
- 'notifications/price': 3, # Get a list of active price alerts
204
- 'favorite/currency_pairs': 3, # Get favorite currency pairs
205
- 'token-scopes': 3, # Get current token scopes
206
- },
207
- 'post': {
208
- 'wallets/burn/{walletId}': 3, # Burns the given wallet
209
- 'wallets/{walletId}/hold_amount': 3, # Move a part of the funds on the wallet to the "hold" to keep it safe from trading
210
- 'wallets/{currencyId}': 3, # Create a wallet for given currency
211
- 'wallets/address/{walletId}': 3, # Create new deposit address
212
- 'addressbook/disable_item/{itemId}': 3, # Disables the address book item
213
- 'addressbook/enable_item/{itemId}': 3, # Enable the address book item
214
- 'addressbook/enable_strict_wd': 3, # Restrict the withdrawals to only addresses that are active in addressbook
215
- 'addressbook/disable_strict_wd': 3, # Remove restriction to withdraw to only addresses that are active in addressbook. E.g. allow to withdraw to any address.
216
- 'withdraw': 30, # Create withdrawal request
217
- 'notifications/price': 3, # Create new price alert
218
- 'referral/program': 3, # Create referral program
219
- 'referral/insert/{code}': 3, # Insert referral code
220
- 'referral/bonus_transfer/{currencyId}': 3, # Transfer referral bonuses balance to main balance for given currency
221
- },
222
- 'put': {
223
- 'favorite/currency_pairs/set': 3, # Set favorite currency pairs
224
- },
225
- 'delete': {
226
- 'addressbook/{itemId}': 3, # Deletes address book item
227
- 'withdraw/{withdrawalId}': 30, # Cancel unconfirmed withdrawal
228
- 'notifications/price/{priceAlertId}': 3, # Delete the price alert by ID
229
- },
230
- },
231
- 'verification': {
232
- 'get': {
233
- 'countries': 1, # Countries list, beta
234
- 'status': 1, # Get status verify
235
- 'fractal/url': 1, # Generate verify url from Fractal
236
- 'smart-id': 1, # Check Smart-ID verify
237
- 'stex': 1, # Get information about your KYC, beta
238
- 'cryptonomica/code': 1, # Get Discount code for Cryptonomica
239
- },
240
- 'post': {
241
- 'smart-id': 1, # Initialization Smart-ID verify(Send request to Smart-ID App)
242
- 'stex': 1, # Update information regarding of your KYC verification, beta
243
- 'cryptonomica': 1, # Add verification from Cryptonomica
244
- },
245
- },
246
- 'settings': {
247
- 'get': {
248
- 'notifications/{event}': 1, # User event notification settings
249
- 'notifications': 1, # User events notification settings
250
- },
251
- 'put': {
252
- 'notifications': 1, # Set notification settings
253
- 'notifications/set': 1,
254
- },
255
- },
256
- },
257
- 'fees': {
258
- 'trading': {
259
- 'tierBased': False,
260
- 'percentage': True,
261
- 'taker': self.parse_number('0.002'),
262
- 'maker': self.parse_number('0.002'),
263
- },
264
- },
265
- 'commonCurrencies': {
266
- 'BC': 'Bitcoin Confidential',
267
- 'BITS': 'Bitcoinus',
268
- 'BITSW': 'BITS',
269
- 'BHD': 'Bithold',
270
- 'BTH': 'Bithereum',
271
- 'MPH': 'Chasyr Token',
272
- 'SBTC': 'SBTCT', # SiamBitcoin
273
- },
274
- 'options': {
275
- 'parseOrderToPrecision': False,
276
- 'networks': {
277
- 'ERC20': 5,
278
- 'ETH': 5,
279
- 'OMNI': 10,
280
- 'XLM': 20,
281
- 'BEP2': 22,
282
- 'TRC20': 24,
283
- 'TRX': 24,
284
- 'SOL': 25,
285
- 'BEP20': 501,
286
- },
287
- 'accountsByType': {
288
- 'spot': 'spot',
289
- 'hold': 'hold',
290
- 'funding': 'funding',
291
- 'referal': 'referal',
292
- },
293
- 'transfer': {
294
- 'fillResponseFromRequest': True,
295
- },
296
- },
297
- 'precisionMode': TICK_SIZE,
298
- 'exceptions': {
299
- 'exact': {
300
- # {"success":false,"message":"Wrong parameters","errors":{"candleType":["Invalid Candle Type!"]}}
301
- # {"success":false,"message":"Wrong parameters","errors":{"time":["timeStart or timeEnd is less then 1"]}}
302
- 'Wrong parameters': BadRequest,
303
- 'Unauthenticated.': AuthenticationError, # {"message":"Unauthenticated."}
304
- 'Server Error': ExchangeError, # {"message": "Server Error"}
305
- 'This feature is only enabled for users verifies by Cryptonomica': PermissionDenied, # {"success":false,"message":"This feature is only enabled for users verifies by Cryptonomica"}
306
- 'Too Many Attempts.': DDoSProtection, # {"message": "Too Many Attempts."}
307
- 'Selected Pair is disabled': BadSymbol, # {"success":false,"message":"Selected Pair is disabled"}
308
- 'Invalid scope(s) provided.': PermissionDenied, # {"message": "Invalid scope(s) provided."}
309
- 'The maximum amount of open orders with the same price cannot exceed 10': InvalidOrder, # {"success":false,"message":"The maximum amount of open orders with the same price cannot exceed 10"}
310
- 'Your account not verified!': AccountSuspended, # {"success":false,"message":"Your account not verified!","unified_message":{"message_id":"verification_required_to_continue","substitutions":null},"notice":"Please be informed that parameter `message` is deprecated and will be removed. Use unified_message instead."}
311
- },
312
- 'broad': {
313
- 'Not enough': InsufficientFunds, # {"success":false,"message":"Not enough ETH"}
314
- },
315
- },
316
- })
317
-
318
- def fetch_currencies(self, params={}):
319
- """
320
- see https://apidocs.stex.com/#tag/Public/paths/~1public~1currencies/get
321
- fetches all available currencies on an exchange
322
- :param dict params: extra parameters specific to the stex api endpoint
323
- :returns dict: an associative dictionary of currencies
324
- """
325
- response = self.publicGetCurrencies(params)
326
- #
327
- # {
328
- # "success":true,
329
- # "data":[
330
- # {
331
- # "id":1,
332
- # "code":"BTC",
333
- # "name":"Bitcoin",
334
- # "active":true,
335
- # "delisted":false,
336
- # "precision":8,
337
- # "minimum_tx_confirmations":1,
338
- # "minimum_withdrawal_amount":"0.00200000",
339
- # "minimum_deposit_amount":"0.00000000",
340
- # "deposit_fee_currency_id":1,
341
- # "deposit_fee_currency_code":"BTC",
342
- # "deposit_fee_const":"0.00000000",
343
- # "deposit_fee_percent":"0.00000000",
344
- # "withdrawal_fee_currency_id":1,
345
- # "withdrawal_fee_currency_code":"BTC",
346
- # "withdrawal_fee_const":"0.00100000",
347
- # "withdrawal_fee_percent":"0.00000000",
348
- # "block_explorer_url":"https:\/\/blockchain.info\/tx\/",
349
- # "protocol_specific_settings":null
350
- # },
351
- # ]
352
- # }
353
- #
354
- result = {}
355
- currencies = self.safe_value(response, 'data', [])
356
- for i in range(0, len(currencies)):
357
- currency = currencies[i]
358
- id = self.safe_string(currency, 'id')
359
- numericId = self.safe_integer(currency, 'id')
360
- # todo: will need to rethink the fees
361
- # to add support for multiple withdrawal/deposit methods and
362
- # differentiated fees for each particular method
363
- code = self.safe_currency_code(self.safe_string(currency, 'code'))
364
- precision = self.parse_number(self.parse_precision(self.safe_string(currency, 'precision')))
365
- fee = self.safe_number(currency, 'withdrawal_fee_const') # todo: redesign
366
- active = self.safe_value(currency, 'active', True)
367
- result[code] = {
368
- 'id': id,
369
- 'numericId': numericId,
370
- 'code': code,
371
- 'info': currency,
372
- 'type': None,
373
- 'name': self.safe_string(currency, 'name'),
374
- 'active': active,
375
- 'deposit': None,
376
- 'withdraw': None,
377
- 'fee': fee,
378
- 'precision': precision,
379
- 'limits': {
380
- 'amount': {
381
- 'min': precision,
382
- 'max': None,
383
- },
384
- 'deposit': {
385
- 'min': self.safe_number(currency, 'minimum_deposit_amount'),
386
- 'max': None,
387
- },
388
- 'withdraw': {
389
- 'min': self.safe_number(currency, 'minimum_withdrawal_amount'),
390
- 'max': None,
391
- },
392
- },
393
- 'networks': {},
394
- }
395
- return result
396
-
397
- def fetch_markets(self, params={}):
398
- """
399
- see https://apidocs.stex.com/#tag/Public/paths/~1public~1currency_pairs~1list~1{code}/get
400
- retrieves data on all markets for stex
401
- :param dict params: extra parameters specific to the exchange api endpoint
402
- :returns [dict]: an array of objects representing market data
403
- """
404
- request = {
405
- 'code': 'ALL',
406
- }
407
- response = self.publicGetCurrencyPairsListCode(self.extend(request, params))
408
- #
409
- # {
410
- # "success":true,
411
- # "data":[
412
- # {
413
- # "id":935,
414
- # "currency_id":662,
415
- # "currency_code":"ABET",
416
- # "currency_name":"Altbet",
417
- # "market_currency_id":1,
418
- # "market_code":"BTC",
419
- # "market_name":"Bitcoin",
420
- # "min_order_amount":"0.00000010",
421
- # "min_buy_price":"0.00000001",
422
- # "min_sell_price":"0.00000001",
423
- # "buy_fee_percent":"0.20000000",
424
- # "sell_fee_percent":"0.20000000",
425
- # "active":true,
426
- # "delisted":false,
427
- # "pair_message":"",
428
- # "currency_precision":8,
429
- # "market_precision":8,
430
- # "symbol":"ABET_BTC",
431
- # "group_name":"BTC",
432
- # "group_id":1
433
- # }
434
- # ]
435
- # }
436
- #
437
- result = []
438
- markets = self.safe_value(response, 'data', [])
439
- for i in range(0, len(markets)):
440
- market = markets[i]
441
- id = self.safe_string(market, 'id')
442
- numericId = self.safe_integer(market, 'id')
443
- baseId = self.safe_string(market, 'currency_id')
444
- quoteId = self.safe_string(market, 'market_currency_id')
445
- baseNumericId = self.safe_integer(market, 'currency_id')
446
- quoteNumericId = self.safe_integer(market, 'market_currency_id')
447
- base = self.safe_currency_code(self.safe_string(market, 'currency_code'))
448
- quote = self.safe_currency_code(self.safe_string(market, 'market_code'))
449
- minBuyPrice = self.safe_string(market, 'min_buy_price')
450
- minSellPrice = self.safe_string(market, 'min_sell_price')
451
- minPrice = Precise.string_max(minBuyPrice, minSellPrice)
452
- buyFee = Precise.string_div(self.safe_string(market, 'buy_fee_percent'), '100')
453
- sellFee = Precise.string_div(self.safe_string(market, 'sell_fee_percent'), '100')
454
- fee = self.parse_number(Precise.string_max(buyFee, sellFee))
455
- result.append({
456
- 'id': id,
457
- 'numericId': numericId,
458
- 'symbol': base + '/' + quote,
459
- 'base': base,
460
- 'quote': quote,
461
- 'settle': None,
462
- 'baseId': baseId,
463
- 'quoteId': quoteId,
464
- 'settleId': None,
465
- 'baseNumericId': baseNumericId,
466
- 'quoteNumericId': quoteNumericId,
467
- 'type': 'spot',
468
- 'spot': True,
469
- 'margin': False,
470
- 'swap': False,
471
- 'future': False,
472
- 'option': False,
473
- 'active': self.safe_value(market, 'active'),
474
- 'contract': False,
475
- 'linear': None,
476
- 'inverse': None,
477
- 'taker': fee,
478
- 'maker': fee,
479
- 'contractSize': None,
480
- 'expiry': None,
481
- 'expiryDatetime': None,
482
- 'strike': None,
483
- 'optionType': None,
484
- 'precision': {
485
- 'amount': self.parse_number(self.parse_precision(self.safe_string(market, 'currency_precision'))),
486
- 'price': self.parse_number(self.parse_precision(self.safe_string(market, 'market_precision'))),
487
- },
488
- 'limits': {
489
- 'leverage': {
490
- 'min': None,
491
- 'max': None,
492
- },
493
- 'amount': {
494
- 'min': self.safe_number(market, 'min_order_amount'),
495
- 'max': None,
496
- },
497
- 'price': {
498
- 'min': minPrice,
499
- 'max': None,
500
- },
501
- 'cost': {
502
- 'min': None,
503
- 'max': None,
504
- },
505
- },
506
- 'info': market,
507
- })
508
- return result
509
-
510
- def fetch_ticker(self, symbol: str, params={}):
511
- """
512
- see https://apidocs.stex.com/#tag/Public/paths/~1public~1ticker~1{currencyPairId}/get
513
- fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
514
- :param str symbol: unified symbol of the market to fetch the ticker for
515
- :param dict params: extra parameters specific to the stex api endpoint
516
- :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
517
- """
518
- self.load_markets()
519
- market = self.market(symbol)
520
- request = {
521
- 'currencyPairId': market['id'],
522
- }
523
- response = self.publicGetTickerCurrencyPairId(self.extend(request, params))
524
- #
525
- # {
526
- # "success": True,
527
- # "data": {
528
- # "id": 2,
529
- # "amount_multiplier": 1,
530
- # "currency_code": "ETH",
531
- # "market_code": "BTC",
532
- # "currency_name": "Ethereum",
533
- # "market_name": "Bitcoin",
534
- # "symbol": "ETH_BTC",
535
- # "group_name": "BTC",
536
- # "group_id": 1,
537
- # "ask": "0.02069998",
538
- # "bid": "0.02028622",
539
- # "last": "0.02049224",
540
- # "open": "0.02059605",
541
- # "low": "0.01977744",
542
- # "high": "0.02097005",
543
- # "volume": "480.43248971",
544
- # "volumeQuote": "23491.29826130",
545
- # "count": "7384",
546
- # "fiatsRate": {
547
- # "USD": 7230.86,
548
- # "EUR": 6590.79,
549
- # "UAH": 173402,
550
- # "AUD": 10595.51,
551
- # "IDR": 101568085,
552
- # "CNY": 50752,
553
- # "KRW": 8452295,
554
- # "JPY": 784607,
555
- # "VND": 167315119,
556
- # "INR": 517596,
557
- # "GBP": 5607.25,
558
- # "CAD": 9602.63,
559
- # "BRL": 30472,
560
- # "RUB": 460718
561
- # },
562
- # "timestamp": 1574698235601
563
- # }
564
- # }
565
- #
566
- ticker = self.safe_value(response, 'data', {})
567
- return self.parse_ticker(ticker, market)
568
-
569
- def fetch_time(self, params={}):
570
- """
571
- see https://apidocs.stex.com/#tag/Public/paths/~1public~1ping/get
572
- fetches the current integer timestamp in milliseconds from the exchange server
573
- :param dict params: extra parameters specific to the stex api endpoint
574
- :returns int: the current integer timestamp in milliseconds from the exchange server
575
- """
576
- response = self.publicGetPing(params)
577
- #
578
- # {
579
- # "success": True,
580
- # "data": {
581
- # "server_datetime": {
582
- # "date": "2019-01-22 15:13:34.233796",
583
- # "timezone_type": 3,
584
- # "timezone": "UTC"
585
- # },
586
- # "server_timestamp": 1548170014
587
- # }
588
- # }
589
- #
590
- data = self.safe_value(response, 'data', {})
591
- serverDatetime = self.safe_value(data, 'server_datetime', {})
592
- return self.parse8601(self.safe_string(serverDatetime, 'date'))
593
-
594
- def fetch_order_book(self, symbol: str, limit: Optional[int] = None, params={}):
595
- """
596
- see https://apidocs.stex.com/#tag/Public/paths/~1public~1orderbook~1{currencyPairId}/get
597
- fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
598
- :param str symbol: unified symbol of the market to fetch the order book for
599
- :param int|None limit: the maximum amount of order book entries to return
600
- :param dict params: extra parameters specific to the stex api endpoint
601
- :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
602
- """
603
- self.load_markets()
604
- market = self.market(symbol)
605
- request = {
606
- 'currencyPairId': market['id'],
607
- }
608
- if limit is not None:
609
- request['limit_bids'] = limit # returns all if set to 0, default 100
610
- request['limit_asks'] = limit # returns all if set to 0, default 100
611
- response = self.publicGetOrderbookCurrencyPairId(self.extend(request, params))
612
- #
613
- # {
614
- # "success": True,
615
- # "data": {
616
- # "ask": [
617
- # {"currency_pair_id": 2, "amount": "2.17865373", "price": "0.02062917", "amount2": "0.04494382", "count": 1, "cumulative_amount": 2.17865373},
618
- # {"currency_pair_id": 2, "amount": "2.27521743", "price": "0.02062918", "amount2": "0.04693587", "count": 1, "cumulative_amount": 4.45387116},
619
- # {"currency_pair_id": 2, "amount": "1.26980049", "price": "0.02063170", "amount2": "0.02619814", "count": 1, "cumulative_amount": 5.72367165},
620
- # ],
621
- # "bid": [
622
- # {"currency_pair_id": 2, "amount": "0.00978005", "price": "0.02057000", "amount2": "0.00020118", "count": 1, "cumulative_amount": 0.00978005},
623
- # {"currency_pair_id": 2, "amount": "0.00500000", "price": "0.02056000", "amount2": "0.00010280", "count": 1, "cumulative_amount": 0.01478005},
624
- # {"currency_pair_id": 2, "amount": "0.77679882", "price": "0.02054001", "amount2": "0.01595546", "count": 1, "cumulative_amount": 0.79157887},
625
- # ],
626
- # "ask_total_amount": 2555.749174609999,
627
- # "bid_total_amount": 29.180037330000005
628
- # }
629
- # }
630
- #
631
- orderbook = self.safe_value(response, 'data', {})
632
- return self.parse_order_book(orderbook, symbol, None, 'bid', 'ask', 'price', 'amount')
633
-
634
- def parse_ticker(self, ticker, market=None):
635
- #
636
- # {
637
- # "id": 2,
638
- # "amount_multiplier": 1,
639
- # "currency_code": "ETH",
640
- # "market_code": "BTC",
641
- # "currency_name": "Ethereum",
642
- # "market_name": "Bitcoin",
643
- # "symbol": "ETH_BTC",
644
- # "group_name": "BTC",
645
- # "group_id": 1,
646
- # "ask": "0.02069998",
647
- # "bid": "0.02028622",
648
- # "last": "0.02049224",
649
- # "open": "0.02059605",
650
- # "low": "0.01977744",
651
- # "high": "0.02097005",
652
- # "volume": "480.43248971",
653
- # "volumeQuote": "23491.29826130",
654
- # "count": "7384",
655
- # "fiatsRate": {
656
- # "USD": 7230.86,
657
- # "EUR": 6590.79,
658
- # "UAH": 173402,
659
- # "AUD": 10595.51,
660
- # "IDR": 101568085,
661
- # "CNY": 50752,
662
- # "KRW": 8452295,
663
- # "JPY": 784607,
664
- # "VND": 167315119,
665
- # "INR": 517596,
666
- # "GBP": 5607.25,
667
- # "CAD": 9602.63,
668
- # "BRL": 30472,
669
- # "RUB": 460718
670
- # },
671
- # "timestamp": 1574698235601
672
- # }
673
- #
674
- timestamp = self.safe_integer(ticker, 'timestamp')
675
- marketId = self.safe_string_2(ticker, 'id', 'symbol')
676
- symbol = self.safe_symbol(marketId, market, '_')
677
- last = self.safe_string(ticker, 'last')
678
- open = self.safe_string(ticker, 'open')
679
- return self.safe_ticker({
680
- 'symbol': symbol,
681
- 'timestamp': timestamp,
682
- 'datetime': self.iso8601(timestamp),
683
- 'high': self.safe_string(ticker, 'high'),
684
- 'low': self.safe_string(ticker, 'low'),
685
- 'bid': self.safe_string(ticker, 'bid'),
686
- 'bidVolume': None,
687
- 'ask': self.safe_string(ticker, 'ask'),
688
- 'askVolume': None,
689
- 'vwap': None,
690
- 'open': open,
691
- 'close': last,
692
- 'last': last,
693
- 'previousClose': None, # previous day close
694
- 'change': None,
695
- 'percentage': None,
696
- 'average': None,
697
- 'baseVolume': self.safe_string(ticker, 'volumeQuote'),
698
- 'quoteVolume': self.safe_string(ticker, 'volume'),
699
- 'info': ticker,
700
- }, market)
701
-
702
- def fetch_tickers(self, symbols: Optional[List[str]] = None, params={}):
703
- """
704
- see https://apidocs.stex.com/#tag/Public/paths/~1public~1ticker/get
705
- fetches price tickers for multiple markets, statistical calculations with the information calculated over the past 24 hours each market
706
- :param [str]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
707
- :param dict params: extra parameters specific to the stex api endpoint
708
- :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
709
- """
710
- self.load_markets()
711
- response = self.publicGetTicker(params)
712
- #
713
- # {
714
- # "success":true,
715
- # "data":[
716
- # {
717
- # "id":262,
718
- # "amount_multiplier":1,
719
- # "currency_code":"ARDR",
720
- # "market_code":"BTC",
721
- # "currency_name":"ARDOR",
722
- # "market_name":"Bitcoin",
723
- # "symbol":"ARDR_BTC",
724
- # "group_name":"BTC",
725
- # "group_id":1,
726
- # "ask":"0.00000630",
727
- # "bid":"0.00000613",
728
- # "last":"0.00000617",
729
- # "open":"0.00000620",
730
- # "low":"0.00000614",
731
- # "high":"0.00000630",
732
- # "volume":"30.37795305",
733
- # "volumeQuote":"4911487.01996544",
734
- # "count":"710",
735
- # "fiatsRate":{
736
- # "USD":7230.86,
737
- # "EUR":6590.79,
738
- # "UAH":173402,
739
- # "AUD":10744.52,
740
- # "IDR":101568085,
741
- # "CNY":50752,
742
- # "KRW":8452295,
743
- # "JPY":784607,
744
- # "VND":167315119,
745
- # "INR":517596,
746
- # "GBP":5607.25,
747
- # "CAD":9602.63,
748
- # "BRL":30472,
749
- # "RUB":467358
750
- # },
751
- # "timestamp":1574698617304,
752
- # "group_position":1
753
- # },
754
- # ]
755
- # }
756
- #
757
- tickers = self.safe_value(response, 'data', [])
758
- return self.parse_tickers(tickers, symbols)
759
-
760
- def parse_ohlcv(self, ohlcv, market=None):
761
- #
762
- # {
763
- # "time": 1566086400000,
764
- # "close": 0.01895,
765
- # "open": 0.01812427,
766
- # "high": 0.0191588,
767
- # "low": 0.01807001,
768
- # "volume": 2588.597813750006
769
- # }
770
- #
771
- return [
772
- self.safe_integer(ohlcv, 'time'),
773
- self.safe_number(ohlcv, 'open'),
774
- self.safe_number(ohlcv, 'high'),
775
- self.safe_number(ohlcv, 'low'),
776
- self.safe_number(ohlcv, 'close'),
777
- self.safe_number(ohlcv, 'volume'),
778
- ]
779
-
780
- def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Optional[int] = None, limit: Optional[int] = None, params={}):
781
- """
782
- see https://apidocs.stex.com/#tag/Public/paths/~1public~1chart~1{currencyPairId}~1{candlesType}/get
783
- fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
784
- :param str symbol: unified symbol of the market to fetch OHLCV data for
785
- :param str timeframe: the length of time each candle represents
786
- :param int|None since: timestamp in ms of the earliest candle to fetch
787
- :param int|None limit: the maximum amount of candles to fetch
788
- :param dict params: extra parameters specific to the stex api endpoint
789
- :returns [[int]]: A list of candles ordered, open, high, low, close, volume
790
- """
791
- self.load_markets()
792
- market = self.market(symbol)
793
- request = {
794
- 'currencyPairId': market['id'],
795
- 'candlesType': self.safe_string(self.timeframes, timeframe, timeframe), # default 1d
796
- # 'timeStart': 1574709092, # unix timestamp in seconds, required
797
- # 'timeEnd': 1574709092, # unix timestamp in seconds, required
798
- # 'limit': 100, # default 100, optional
799
- # 'offset' 100, # optional, pagination within timerange
800
- }
801
- if limit is None:
802
- limit = 100
803
- else:
804
- request['limit'] = limit
805
- duration = self.parse_timeframe(timeframe)
806
- timerange = limit * duration
807
- if since is None:
808
- request['timeEnd'] = self.seconds()
809
- request['timeStart'] = request['timeEnd'] - timerange
810
- else:
811
- request['timeStart'] = self.parse_to_int(since / 1000)
812
- request['timeEnd'] = self.sum(request['timeStart'], timerange)
813
- response = self.publicGetChartCurrencyPairIdCandlesType(self.extend(request, params))
814
- #
815
- # {
816
- # "success": True,
817
- # "data": [
818
- # {
819
- # "time": 1566086400000,
820
- # "close": 0.01895,
821
- # "open": 0.01812427,
822
- # "high": 0.0191588,
823
- # "low": 0.01807001,
824
- # "volume": 2588.597813750006
825
- # },
826
- # ]
827
- # }
828
- #
829
- data = self.safe_value(response, 'data', [])
830
- return self.parse_ohlcvs(data, market, timeframe, since, limit)
831
-
832
- def parse_trade(self, trade, market=None):
833
- #
834
- # public fetchTrades
835
- #
836
- # {
837
- # "id": 35989317,
838
- # "price": "0.02033813",
839
- # "amount": "3.60000000",
840
- # "type": "BUY",
841
- # "timestamp": "1574713503"
842
- # }
843
- #
844
- # private fetchMyTrades, fetchClosedOrder, fetchOrderTrades
845
- #
846
- # {
847
- # "id": 658745,
848
- # "buy_order_id": 6587453,
849
- # "sell_order_id": 6587459,
850
- # "price": 0.012285,
851
- # "amount": 6.35,
852
- # "trade_type": "SELL",
853
- # "timestamp": "1538737692"
854
- # }
855
- #
856
- id = self.safe_string(trade, 'id')
857
- timestamp = self.safe_timestamp(trade, 'timestamp')
858
- priceString = self.safe_string(trade, 'price')
859
- amountString = self.safe_string(trade, 'amount')
860
- symbol = None
861
- if (symbol is None) and (market is not None):
862
- symbol = market['symbol']
863
- side = self.safe_string_lower_2(trade, 'type', 'trade_type')
864
- return self.safe_trade({
865
- 'info': trade,
866
- 'timestamp': timestamp,
867
- 'datetime': self.iso8601(timestamp),
868
- 'symbol': symbol,
869
- 'id': id,
870
- 'order': None,
871
- 'type': None,
872
- 'takerOrMaker': None,
873
- 'side': side,
874
- 'price': priceString,
875
- 'amount': amountString,
876
- 'cost': None,
877
- 'fee': None,
878
- }, market)
879
-
880
- def fetch_trades(self, symbol: str, since: Optional[int] = None, limit: Optional[int] = None, params={}):
881
- """
882
- see https://apidocs.stex.com/#tag/Public/paths/~1public~1trades~1{currencyPairId}/get
883
- get the list of most recent trades for a particular symbol
884
- :param str symbol: unified symbol of the market to fetch trades for
885
- :param int|None since: timestamp in ms of the earliest trade to fetch
886
- :param int|None limit: the maximum amount of trades to fetch
887
- :param dict params: extra parameters specific to the stex api endpoint
888
- :returns [dict]: a list of `trade structures <https://docs.ccxt.com/en/latest/manual.html?#public-trades>`
889
- """
890
- self.load_markets()
891
- market = self.market(symbol)
892
- request = {
893
- 'currencyPairId': market['id'],
894
- # 'sort': 'ASC', # ASC or DESC, default DESC
895
- # 'from': 1574709092, # unix timestamp, optional
896
- # 'till': 1574709092, # unix timestamp, optional
897
- # 'limit': 100, # default 100, optional
898
- # 'offset': 100, # optional
899
- }
900
- if limit is not None:
901
- request['limit'] = limit # currently limited to 100 or fewer
902
- if since is not None:
903
- request['sort'] = 'ASC' # needed to make the from param work
904
- request['from'] = self.parse_to_int(since / 1000)
905
- response = self.publicGetTradesCurrencyPairId(self.extend(request, params))
906
- #
907
- # {
908
- # "success": True,
909
- # "data": [
910
- # {
911
- # "id": 35989317,
912
- # "price": "0.02033813",
913
- # "amount": "3.60000000",
914
- # "type": "BUY",
915
- # "timestamp": "1574713503"
916
- # },
917
- # ]
918
- # }
919
- #
920
- trades = self.safe_value(response, 'data', [])
921
- return self.parse_trades(trades, market, since, limit)
922
-
923
- def fetch_trading_fee(self, symbol: str, params={}):
924
- """
925
- see https://apidocs.stex.com/#tag/Trading/paths/~1trading~1fees~1{currencyPairId}/get
926
- fetch the trading fees for a market
927
- :param str symbol: unified market symbol
928
- :param dict params: extra parameters specific to the stex api endpoint
929
- :returns dict: a `fee structure <https://docs.ccxt.com/#/?id=fee-structure>`
930
- """
931
- self.load_markets()
932
- market = self.market(symbol)
933
- request = {
934
- 'currencyPairId': market['id'],
935
- }
936
- response = self.tradingGetFeesCurrencyPairId(self.extend(request, params))
937
- #
938
- # {
939
- # success: True,
940
- # data: {buy_fee: '0.00200000', sell_fee: '0.00200000'},
941
- # unified_message: {message_id: 'operation_successful', substitutions: []}
942
- # }
943
- #
944
- data = self.safe_value(response, 'data')
945
- return {
946
- 'info': response,
947
- 'symbol': market['symbol'],
948
- 'maker': self.safe_number(data, 'sell_fee'),
949
- 'taker': self.safe_number(data, 'buy_fee'),
950
- 'percentage': True,
951
- 'tierBased': True,
952
- }
953
-
954
- def parse_balance(self, response):
955
- result = {
956
- 'info': response,
957
- 'timestamp': None,
958
- 'datetime': None,
959
- }
960
- balances = self.safe_value(response, 'data', [])
961
- for i in range(0, len(balances)):
962
- balance = balances[i]
963
- code = self.safe_currency_code(self.safe_string(balance, 'currency_id'))
964
- account = self.account()
965
- account['free'] = self.safe_string(balance, 'balance')
966
- account['used'] = self.safe_string(balance, 'frozen_balance')
967
- result[code] = account
968
- return self.safe_balance(result)
969
-
970
- def fetch_balance(self, params={}):
971
- """
972
- see https://apidocs.stex.com/#tag/Profile/paths/~1profile~1wallets/get
973
- query for balance and get the amount of funds available for trading or funds locked in orders
974
- :param dict params: extra parameters specific to the stex api endpoint
975
- :returns dict: a `balance structure <https://docs.ccxt.com/en/latest/manual.html?#balance-structure>`
976
- """
977
- self.load_markets()
978
- # self.load_accounts()
979
- response = self.profileGetWallets(params)
980
- #
981
- # {
982
- # "success": True,
983
- # "data": [
984
- # {
985
- # "id": null,
986
- # "currency_id": 665,
987
- # "delisted": False,
988
- # "disabled": False,
989
- # "disable_deposits": False,
990
- # "currency_code": "ORM",
991
- # "currency_name": "Orium",
992
- # "currency_type_id": 5,
993
- # "balance": "0",
994
- # "frozen_balance": "0",
995
- # "bonus_balance": "0",
996
- # "total_balance": "0",
997
- # "protocol_specific_settings": null,
998
- # "rates": {"BTC": "0.00000000020", "USD": "0.00000147"},
999
- # },
1000
- # {
1001
- # "id": null,
1002
- # "currency_id": 272,
1003
- # "delisted": False,
1004
- # "disabled": False,
1005
- # "disable_deposits": False,
1006
- # "currency_code": "USDT",
1007
- # "currency_name": "TetherUSD",
1008
- # "currency_type_id": 23,
1009
- # "balance": "0",
1010
- # "frozen_balance": "0",
1011
- # "bonus_balance": "0",
1012
- # "total_balance": "0",
1013
- # "protocol_specific_settings": [
1014
- # {"protocol_name": "OMNI", "protocol_id": 10, "active": True, "withdrawal_fee_currency_id": 272, "withdrawal_fee_const": 10, "withdrawal_fee_percent": 0, "block_explorer_url": "https://omniexplorer.info/search/"},
1015
- # {"protocol_name": "ERC20", "protocol_id": 5, "active": True, "withdrawal_fee_const": 1.2, "withdrawal_fee_percent": 0, "block_explorer_url": "https://etherscan.io/tx/"},
1016
- # {"protocol_name": "TRON", "protocol_id": 24, "active": True, "withdrawal_fee_currency_id": 272, "withdrawal_fee_const": 0.2, "withdrawal_fee_percent": 0, "block_explorer_url": "https://tronscan.org/#/transaction/"}
1017
- # ],
1018
- # "rates": {"BTC": "0.00013893", "USD": "1"},
1019
- # },
1020
- # ]
1021
- # }
1022
- #
1023
- return self.parse_balance(response)
1024
-
1025
- def parse_order_status(self, status):
1026
- statuses = {
1027
- 'PROCESSING': 'open',
1028
- 'PENDING': 'open',
1029
- 'PARTIAL': 'open',
1030
- 'FINISHED': 'closed',
1031
- 'CANCELLED': 'canceled',
1032
- }
1033
- return self.safe_string(statuses, status, status)
1034
-
1035
- def parse_order(self, order, market=None):
1036
- #
1037
- # createOrder, fetchOpenOrders, fetchClosedOrders, cancelOrder, fetchOrder, fetchClosedOrder
1038
- #
1039
- # {
1040
- # "id": 828680665,
1041
- # "currency_pair_id": 1,
1042
- # "currency_pair_name": "NXT_BTC",
1043
- # "price": "0.011384",
1044
- # "trigger_price": 0.011385,
1045
- # "initial_amount": "13.942",
1046
- # "processed_amount": "3.724", # missing in fetchClosedOrder
1047
- # "type": "SELL",
1048
- # "original_type": "STOP_LIMIT_SELL",
1049
- # "created": "2019-01-17 10:14:48",
1050
- # "timestamp": "1547720088",
1051
- # "status": "PARTIAL"
1052
- # # fetchClosedOrder only
1053
- # "trades": [
1054
- # {
1055
- # "id": 658745,
1056
- # "buy_order_id": 658745,
1057
- # "sell_order_id": 828680665,
1058
- # "price": 0.012285,
1059
- # "amount": 6.35,
1060
- # "trade_type": "SELL",
1061
- # "timestamp": "1538737692"
1062
- # }
1063
- # ],
1064
- # # fetchClosedOrder only
1065
- # "fees": [
1066
- # {
1067
- # "id": 1234567,
1068
- # "currency_id": 1,
1069
- # "amount": 0.00025,
1070
- # "timestamp": "1548149238"
1071
- # }
1072
- # ]
1073
- # }
1074
- #
1075
- id = self.safe_string(order, 'id')
1076
- status = self.parse_order_status(self.safe_string(order, 'status'))
1077
- marketId = self.safe_string_2(order, 'currency_pair_id', 'currency_pair_name')
1078
- symbol = self.safe_symbol(marketId, market, '_')
1079
- timestamp = self.safe_timestamp(order, 'timestamp')
1080
- price = self.safe_string(order, 'price')
1081
- amount = self.safe_string(order, 'initial_amount')
1082
- filled = self.safe_string(order, 'processed_amount')
1083
- remaining = None
1084
- cost = None
1085
- if filled is not None:
1086
- if amount is not None:
1087
- remaining = Precise.string_sub(amount, filled)
1088
- if self.options['parseOrderToPrecision']:
1089
- remaining = self.amount_to_precision(symbol, remaining)
1090
- remaining = Precise.string_max(remaining, '0.0')
1091
- if price is not None:
1092
- if cost is None:
1093
- cost = Precise.string_mul(price, filled)
1094
- type = self.safe_string(order, 'original_type')
1095
- if (type == 'BUY') or (type == 'SELL'):
1096
- type = None
1097
- side = self.safe_string_lower(order, 'type')
1098
- trades = self.safe_value(order, 'trades')
1099
- stopPrice = self.safe_number(order, 'trigger_price')
1100
- result = {
1101
- 'info': order,
1102
- 'id': id,
1103
- 'clientOrderId': None,
1104
- 'timestamp': timestamp,
1105
- 'datetime': self.iso8601(timestamp),
1106
- 'lastTradeTimestamp': None,
1107
- 'symbol': symbol,
1108
- 'type': type,
1109
- 'timeInForce': None,
1110
- 'postOnly': None,
1111
- 'side': side,
1112
- 'price': price,
1113
- 'stopPrice': stopPrice,
1114
- 'triggerPrice': stopPrice,
1115
- 'amount': amount,
1116
- 'cost': cost,
1117
- 'average': None,
1118
- 'filled': filled,
1119
- 'remaining': remaining,
1120
- 'status': status,
1121
- 'trades': trades,
1122
- }
1123
- fees = self.safe_value(order, 'fees')
1124
- if fees is None:
1125
- result['fee'] = None
1126
- else:
1127
- numFees = len(fees)
1128
- if numFees > 0:
1129
- result['fees'] = []
1130
- for i in range(0, len(fees)):
1131
- feeCost = self.safe_string(fees[i], 'amount')
1132
- if feeCost is not None:
1133
- feeCurrencyId = self.safe_string(fees[i], 'currency_id')
1134
- feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
1135
- result['fees'].append({
1136
- 'cost': feeCost,
1137
- 'currency': feeCurrencyCode,
1138
- })
1139
- else:
1140
- result['fee'] = None
1141
- return self.safe_order(result, market)
1142
-
1143
- def create_order(self, symbol: str, type, side: OrderSide, amount, price=None, params={}):
1144
- """
1145
- see https://apidocs.stex.com/#tag/Trading/paths/~1trading~1orders~1{currencyPairId}/post
1146
- create a trade order
1147
- :param str symbol: unified symbol of the market to create an order in
1148
- :param str type: 'market' or 'limit'
1149
- :param str side: 'buy' or 'sell'
1150
- :param float amount: how much of currency you want to trade in units of base currency
1151
- :param float|None price: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1152
- :param dict params: extra parameters specific to the stex api endpoint
1153
- :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1154
- """
1155
- if type == 'market':
1156
- raise ExchangeError(self.id + ' createOrder() allows limit orders only')
1157
- self.load_markets()
1158
- market = self.market(symbol)
1159
- if type == 'limit':
1160
- type = side
1161
- request = {
1162
- 'currencyPairId': market['id'],
1163
- 'type': type.upper(), # 'BUY', 'SELL', 'STOP_LIMIT_BUY', 'STOP_LIMIT_SELL'
1164
- 'amount': float(self.amount_to_precision(symbol, amount)), # required
1165
- 'price': float(self.price_to_precision(symbol, price)), # required
1166
- # 'trigger_price': 123.45 # required for STOP_LIMIT_BUY or STOP_LIMIT_SELL
1167
- }
1168
- response = self.tradingPostOrdersCurrencyPairId(self.extend(request, params))
1169
- #
1170
- # {
1171
- # "success": True,
1172
- # "data": {
1173
- # "id": 828680665,
1174
- # "currency_pair_id": 1,
1175
- # "currency_pair_name": "NXT_BTC",
1176
- # "price": "0.011384",
1177
- # "trigger_price": 0.011385,
1178
- # "initial_amount": "13.942",
1179
- # "processed_amount": "3.724",
1180
- # "type": "SELL",
1181
- # "original_type": "STOP_LIMIT_SELL",
1182
- # "created": "2019-01-17 10:14:48",
1183
- # "timestamp": "1547720088",
1184
- # "status": "PARTIAL"
1185
- # }
1186
- # }
1187
- #
1188
- data = self.safe_value(response, 'data', {})
1189
- return self.parse_order(data, market)
1190
-
1191
- def fetch_order(self, id: str, symbol: Optional[str] = None, params={}):
1192
- """
1193
- see https://apidocs.stex.com/#tag/Trading/paths/~1trading~1order~1{orderId}/get
1194
- fetches information on an order made by the user
1195
- :param str|None symbol: unified symbol of the market the order was made in
1196
- :param dict params: extra parameters specific to the stex api endpoint
1197
- :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1198
- """
1199
- self.load_markets()
1200
- request = {
1201
- 'orderId': id,
1202
- }
1203
- response = self.tradingGetOrderOrderId(self.extend(request, params))
1204
- #
1205
- # {
1206
- # "success": True,
1207
- # "data": {
1208
- # "id": 828680665,
1209
- # "currency_pair_id": 1,
1210
- # "currency_pair_name": "NXT_BTC",
1211
- # "price": "0.011384",
1212
- # "trigger_price": 0.011385,
1213
- # "initial_amount": "13.942",
1214
- # "processed_amount": "3.724",
1215
- # "type": "SELL",
1216
- # "original_type": "STOP_LIMIT_SELL",
1217
- # "created": "2019-01-17 10:14:48",
1218
- # "timestamp": "1547720088",
1219
- # "status": "PARTIAL"
1220
- # }
1221
- # }
1222
- #
1223
- data = self.safe_value(response, 'data', {})
1224
- market = None
1225
- if symbol is not None:
1226
- market = self.market(symbol)
1227
- return self.parse_order(data, market)
1228
-
1229
- def fetch_closed_order(self, id: str, symbol: Optional[str] = None, params={}):
1230
- """
1231
- see https://apidocs.stex.com/#tag/Trading-History-and-Reports/paths/~1reports~1orders~1{orderId}/get
1232
- fetch an open order by it's id
1233
- :param str id: order id
1234
- :param str|None symbol: unified market symbol, default is None
1235
- :param dict params: extra parameters specific to the stex api endpoint
1236
- :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1237
- """
1238
- self.load_markets()
1239
- request = {
1240
- 'orderId': id,
1241
- }
1242
- response = self.reportsGetOrdersOrderId(self.extend(request, params))
1243
- #
1244
- # {
1245
- # "success": True,
1246
- # "data": {
1247
- # "id": 5478965,
1248
- # "currency_pair_id": 1,
1249
- # "currency_pair_name": "NXT_BTC",
1250
- # "price": "0.00013800",
1251
- # "initial_amount": "1.00000000",
1252
- # "type": "BUY",
1253
- # "created": "2019-01-22 09:27:17",
1254
- # "timestamp": 1548149237,
1255
- # "status": "FINISHED",
1256
- # "trades": [
1257
- # {
1258
- # "id": 658745,
1259
- # "buy_order_id": 6587453,
1260
- # "sell_order_id": 6587459,
1261
- # "price": 0.012285,
1262
- # "amount": 6.35,
1263
- # "trade_type": "SELL",
1264
- # "timestamp": "1538737692"
1265
- # }
1266
- # ],
1267
- # "fees": [
1268
- # {
1269
- # "id": 1234567,
1270
- # "currency_id": 1,
1271
- # "amount": 0.00025,
1272
- # "timestamp": "1548149238"
1273
- # }
1274
- # ]
1275
- # }
1276
- # }
1277
- #
1278
- data = self.safe_value(response, 'data', {})
1279
- market = None
1280
- if symbol is not None:
1281
- market = self.market(symbol)
1282
- return self.parse_order(data, market)
1283
-
1284
- def fetch_order_trades(self, id: str, symbol: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
1285
- """
1286
- fetch all the trades made from a single order
1287
- :param str id: order id
1288
- :param str|None symbol: unified market symbol
1289
- :param int|None since: the earliest time in ms to fetch trades for
1290
- :param int|None limit: the maximum number of trades to retrieve
1291
- :param dict params: extra parameters specific to the stex api endpoint
1292
- :returns [dict]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
1293
- """
1294
- order = self.fetch_closed_order(id, symbol, params)
1295
- return order['trades']
1296
-
1297
- def fetch_open_orders(self, symbol: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
1298
- """
1299
- see https://apidocs.stex.com/#tag/Trading/paths/~1trading~1orders/get
1300
- see https://apidocs.stex.com/#tag/Trading/paths/~1trading~1orders~1{currencyPairId}/get
1301
- fetch all unfilled currently open orders
1302
- :param str|None symbol: unified market symbol
1303
- :param int|None since: the earliest time in ms to fetch open orders for
1304
- :param int|None limit: the maximum number of open orders structures to retrieve
1305
- :param dict params: extra parameters specific to the stex api endpoint
1306
- :returns [dict]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1307
- """
1308
- self.load_markets()
1309
- market = None
1310
- method = 'tradingGetOrders'
1311
- request = {
1312
- # 'limit': 100, # default 100
1313
- # 'offset': 100,
1314
- }
1315
- if symbol is not None:
1316
- method = 'tradingGetOrdersCurrencyPairId'
1317
- market = self.market(symbol)
1318
- request['currencyPairId'] = market['id']
1319
- if limit is not None:
1320
- request['limit'] = limit
1321
- response = getattr(self, method)(self.extend(request, params))
1322
- #
1323
- # {
1324
- # "success": True,
1325
- # "data": [
1326
- # {
1327
- # "id": 828680665,
1328
- # "currency_pair_id": 1,
1329
- # "currency_pair_name": "NXT_BTC",
1330
- # "price": "0.011384",
1331
- # "trigger_price": 0.011385,
1332
- # "initial_amount": "13.942",
1333
- # "processed_amount": "3.724",
1334
- # "type": "SELL",
1335
- # "original_type": "STOP_LIMIT_SELL",
1336
- # "created": "2019-01-17 10:14:48",
1337
- # "timestamp": "1547720088",
1338
- # "status": "PARTIAL"
1339
- # }
1340
- # ]
1341
- # }
1342
- #
1343
- data = self.safe_value(response, 'data', [])
1344
- return self.parse_orders(data, market, since, limit)
1345
-
1346
- def cancel_order(self, id: str, symbol: Optional[str] = None, params={}):
1347
- """
1348
- see https://apidocs.stex.com/#tag/Trading/paths/~1trading~1order~1{orderId}/delete
1349
- cancels an open order
1350
- :param str id: order id
1351
- :param str|None symbol: not used by stex cancelOrder()
1352
- :param dict params: extra parameters specific to the stex api endpoint
1353
- :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1354
- """
1355
- self.load_markets()
1356
- request = {
1357
- 'orderId': id,
1358
- }
1359
- response = self.tradingDeleteOrderOrderId(self.extend(request, params))
1360
- #
1361
- # {
1362
- # "success": True,
1363
- # "data": {
1364
- # "put_into_processing_queue": [
1365
- # {
1366
- # "id": 828680665,
1367
- # "currency_pair_id": 1,
1368
- # "currency_pair_name": "NXT_BTC",
1369
- # "price": "0.011384",
1370
- # "trigger_price": 0.011385,
1371
- # "initial_amount": "13.942",
1372
- # "processed_amount": "3.724",
1373
- # "type": "SELL",
1374
- # "original_type": "STOP_LIMIT_SELL",
1375
- # "created": "2019-01-17 10:14:48",
1376
- # "timestamp": "1547720088",
1377
- # "status": "PARTIAL"
1378
- # }
1379
- # ],
1380
- # "not_put_into_processing_queue": [
1381
- # {
1382
- # "id": 828680665,
1383
- # "currency_pair_id": 1,
1384
- # "currency_pair_name": "NXT_BTC",
1385
- # "price": "0.011384",
1386
- # "trigger_price": 0.011385,
1387
- # "initial_amount": "13.942",
1388
- # "processed_amount": "3.724",
1389
- # "type": "SELL",
1390
- # "original_type": "STOP_LIMIT_SELL",
1391
- # "created": "2019-01-17 10:14:48",
1392
- # "timestamp": "1547720088",
1393
- # "status": "PARTIAL"
1394
- # }
1395
- # ],
1396
- # "message": "string"
1397
- # }
1398
- # }
1399
- #
1400
- data = self.safe_value(response, 'data', {})
1401
- acceptedOrders = self.safe_value(data, 'put_into_processing_queue', [])
1402
- rejectedOrders = self.safe_value(data, 'not_put_into_processing_queue', [])
1403
- numAcceptedOrders = len(acceptedOrders)
1404
- numRejectedOrders = len(rejectedOrders)
1405
- if numAcceptedOrders < 1:
1406
- if numRejectedOrders < 1:
1407
- raise OrderNotFound(self.id + ' cancelOrder() received an empty response: ' + self.json(response))
1408
- else:
1409
- return self.parse_order(rejectedOrders[0])
1410
- else:
1411
- if numRejectedOrders < 1:
1412
- return self.parse_order(acceptedOrders[0])
1413
- else:
1414
- raise OrderNotFound(self.id + ' cancelOrder() received an empty response: ' + self.json(response))
1415
-
1416
- def cancel_all_orders(self, symbol: Optional[str] = None, params={}):
1417
- """
1418
- see https://apidocs.stex.com/#tag/Trading/paths/~1trading~1orders/delete
1419
- see https://apidocs.stex.com/#tag/Trading/paths/~1trading~1orders~1{currencyPairId}/delete
1420
- cancel all open orders
1421
- :param str|None symbol: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
1422
- :param dict params: extra parameters specific to the stex api endpoint
1423
- :returns [dict]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1424
- """
1425
- self.load_markets()
1426
- request = {}
1427
- method = 'tradingDeleteOrders'
1428
- if symbol is not None:
1429
- market = self.market(symbol)
1430
- request['currencyPairId'] = market['id']
1431
- method = 'tradingDeleteOrdersCurrencyPairId'
1432
- response = getattr(self, method)(self.extend(request, params))
1433
- #
1434
- # {
1435
- # "success":true,
1436
- # "data":{
1437
- # "put_into_processing_queue":[],
1438
- # "not_put_into_processing_queue":[],
1439
- # "message":"Orders operations are handled in processing queue, therefore cancelling is not immediate."
1440
- # }
1441
- # }
1442
- #
1443
- return response
1444
-
1445
- def fetch_my_trades(self, symbol: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
1446
- """
1447
- see https://apidocs.stex.com/#tag/Trading-History-and-Reports/paths/~1reports~1trades~1{currencyPairId}/get
1448
- fetch all trades made by the user
1449
- :param str symbol: unified market symbol
1450
- :param int|None since: the earliest time in ms to fetch trades for
1451
- :param int|None limit: the maximum number of trades structures to retrieve
1452
- :param dict params: extra parameters specific to the stex api endpoint
1453
- :returns [dict]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
1454
- """
1455
- if symbol is None:
1456
- raise ArgumentsRequired(self.id + ' fetchMyTrades() requires a symbol argument')
1457
- self.load_markets()
1458
- market = self.market(symbol)
1459
- request = {
1460
- 'currencyPairId': market['id'],
1461
- # 'timeStart': '2019-11-26T19:54:55.901Z', # datetime in iso format
1462
- # 'timeEnd': '2019-11-26T19:54:55.901Z', # datetime in iso format
1463
- # 'limit': 100, # default 100
1464
- # 'offset': 100,
1465
- }
1466
- if since is not None:
1467
- request['timeStart'] = self.iso8601(since)
1468
- if limit is not None:
1469
- request['limit'] = limit
1470
- response = self.reportsGetTradesCurrencyPairId(self.extend(request, params))
1471
- #
1472
- # {
1473
- # "success": True,
1474
- # "data": [
1475
- # {
1476
- # "id": 658745,
1477
- # "buy_order_id": 6587453,
1478
- # "sell_order_id": 6587459,
1479
- # "price": 0.012285,
1480
- # "amount": 6.35,
1481
- # "trade_type": "SELL",
1482
- # "timestamp": "1538737692"
1483
- # }
1484
- # ]
1485
- # }
1486
- #
1487
- trades = self.safe_value(response, 'data', [])
1488
- return self.parse_trades(trades, market, since, limit)
1489
-
1490
- def create_deposit_address(self, code: str, params={}):
1491
- """
1492
- see https://apidocs.stex.com/#tag/Profile/paths/~1profile~1wallets~1{currencyId}/post
1493
- create a currency deposit address
1494
- :param str code: unified currency code of the currency for the deposit address
1495
- :param dict params: extra parameters specific to the stex api endpoint
1496
- :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
1497
- """
1498
- self.load_markets()
1499
- currency = self.currency(code)
1500
- request = {
1501
- 'currencyId': currency['id'],
1502
- # Default value is the value that represents legacy protocol.
1503
- # In case of USDT it is 10 OMNI was the default previously.
1504
- # The list of protocols can be obtained from the /public/currencies/{currencyId}
1505
- # 'protocol_id': 10,
1506
- }
1507
- response = self.profilePostWalletsCurrencyId(self.extend(request, params))
1508
- #
1509
- # {
1510
- # "success": True,
1511
- # "data": {
1512
- # "id": 45875,
1513
- # "currency_id": 1,
1514
- # "delisted": False,
1515
- # "disabled": False,
1516
- # "disable_deposits": False,
1517
- # "code": "BTC",
1518
- # "balance": "0.198752",
1519
- # "frozen_balance": "1.5784",
1520
- # "bonus_balance": "0.000",
1521
- # "deposit_address": {
1522
- # "address": "0X12WERTYUIIJHGFVBNMJHGDFGHJ765SDFGHJ",
1523
- # "address_name": "Address",
1524
- # "additional_address_parameter": "qwertyuiopasdfghjkl",
1525
- # "additional_address_parameter_name": "Destination Tag",
1526
- # "notification": "",
1527
- # "protocol_id": 10,
1528
- # "protocol_name": "Tether OMNI",
1529
- # "supports_new_address_creation": False
1530
- # },
1531
- # "multi_deposit_addresses": [
1532
- # {
1533
- # "address": "0X12WERTYUIIJHGFVBNMJHGDFGHJ765SDFGHJ",
1534
- # "address_name": "Address",
1535
- # "additional_address_parameter": "qwertyuiopasdfghjkl",
1536
- # "additional_address_parameter_name": "Destination Tag",
1537
- # "notification": "",
1538
- # "protocol_id": 10,
1539
- # "protocol_name": "Tether OMNI",
1540
- # "supports_new_address_creation": False
1541
- # }
1542
- # ],
1543
- # "withdrawal_additional_field_name": "Payment ID(optional)",
1544
- # "rates": {"BTC": 0.000001},
1545
- # "protocol_specific_settings": [
1546
- # {
1547
- # "protocol_name": "Tether OMNI",
1548
- # "protocol_id": 10,
1549
- # "active": True,
1550
- # "withdrawal_fee_currency_id": 1,
1551
- # "withdrawal_fee_const": 0.002,
1552
- # "withdrawal_fee_percent": 0,
1553
- # "block_explorer_url": "https://omniexplorer.info/search/"
1554
- # }
1555
- # ]
1556
- # }
1557
- # }
1558
- #
1559
- data = self.safe_value(response, 'data', {})
1560
- depositAddress = self.safe_value(data, 'deposit_address', {})
1561
- address = self.safe_string(depositAddress, 'address')
1562
- tag = self.safe_string(depositAddress, 'additional_address_parameter')
1563
- self.check_address(address)
1564
- return {
1565
- 'currency': code,
1566
- 'address': address,
1567
- 'tag': tag,
1568
- 'info': response,
1569
- }
1570
-
1571
- def fetch_deposit_address(self, code: str, params={}):
1572
- """
1573
- see https://apidocs.stex.com/#tag/Profile/paths/~1profile~1wallets~1{walletId}/get
1574
- fetch the deposit address for a currency associated with self account
1575
- :param str code: unified currency code
1576
- :param dict params: extra parameters specific to the stex api endpoint
1577
- :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
1578
- """
1579
- self.load_markets()
1580
- balance = self.fetch_balance()
1581
- wallets = self.safe_value(balance['info'], 'data', [])
1582
- walletsByCurrencyId = self.index_by(wallets, 'currency_id')
1583
- currency = self.currency(code)
1584
- wallet = self.safe_value(walletsByCurrencyId, currency['id'])
1585
- if wallet is None:
1586
- raise ExchangeError(self.id + ' fetchDepositAddress() could not find the wallet id for currency code ' + code + ', try to call createDepositAddress() first')
1587
- walletId = self.safe_integer(wallet, 'id')
1588
- if walletId is None:
1589
- raise ExchangeError(self.id + ' fetchDepositAddress() could not find the wallet id for currency code ' + code + ', try to call createDepositAddress() first')
1590
- request = {
1591
- 'walletId': walletId,
1592
- }
1593
- response = self.profileGetWalletsWalletId(self.extend(request, params))
1594
- #
1595
- # {
1596
- # "success": True,
1597
- # "data": {
1598
- # "id": 45875,
1599
- # "currency_id": 1,
1600
- # "delisted": False,
1601
- # "disabled": False,
1602
- # "disable_deposits": False,
1603
- # "code": "BTC",
1604
- # "balance": "0.198752",
1605
- # "frozen_balance": "1.5784",
1606
- # "bonus_balance": "0.000",
1607
- # "deposit_address": {
1608
- # "address": "0X12WERTYUIIJHGFVBNMJHGDFGHJ765SDFGHJ",
1609
- # "address_name": "Address",
1610
- # "additional_address_parameter": "qwertyuiopasdfghjkl",
1611
- # "additional_address_parameter_name": "Destination Tag",
1612
- # "notification": "",
1613
- # "protocol_id": 10,
1614
- # "protocol_name": "Tether OMNI",
1615
- # "supports_new_address_creation": False
1616
- # },
1617
- # "multi_deposit_addresses": [
1618
- # {
1619
- # "address": "0X12WERTYUIIJHGFVBNMJHGDFGHJ765SDFGHJ",
1620
- # "address_name": "Address",
1621
- # "additional_address_parameter": "qwertyuiopasdfghjkl",
1622
- # "additional_address_parameter_name": "Destination Tag",
1623
- # "notification": "",
1624
- # "protocol_id": 10,
1625
- # "protocol_name": "Tether OMNI",
1626
- # "supports_new_address_creation": False
1627
- # }
1628
- # ],
1629
- # "withdrawal_additional_field_name": "Payment ID(optional)",
1630
- # "rates": {"BTC": 0.000001},
1631
- # "protocol_specific_settings": [
1632
- # {
1633
- # "protocol_name": "Tether OMNI",
1634
- # "protocol_id": 10,
1635
- # "active": True,
1636
- # "withdrawal_fee_currency_id": 1,
1637
- # "withdrawal_fee_const": 0.002,
1638
- # "withdrawal_fee_percent": 0,
1639
- # "block_explorer_url": "https://omniexplorer.info/search/"
1640
- # }
1641
- # ]
1642
- # }
1643
- # }
1644
- #
1645
- data = self.safe_value(response, 'data', [])
1646
- depositAddress = self.safe_value(data, 'deposit_address', {})
1647
- address = self.safe_string(depositAddress, 'address')
1648
- tag = self.safe_string(depositAddress, 'additional_address_parameter')
1649
- self.check_address(address)
1650
- return {
1651
- 'currency': code,
1652
- 'address': address,
1653
- 'tag': tag,
1654
- 'network': None,
1655
- 'info': response,
1656
- }
1657
-
1658
- def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
1659
- url = self.urls['api']['rest'] + '/' + api + '/' + self.implode_params(path, params)
1660
- query = self.omit(params, self.extract_params(path))
1661
- if api == 'public':
1662
- if query:
1663
- url += '?' + self.urlencode(query)
1664
- else:
1665
- self.check_required_credentials()
1666
- headers = {
1667
- 'Authorization': 'Bearer ' + self.token,
1668
- }
1669
- if method == 'GET' or method == 'DELETE':
1670
- if query:
1671
- url += '?' + self.urlencode(query)
1672
- else:
1673
- body = self.json(query)
1674
- if query:
1675
- headers['Content-Type'] = 'application/json'
1676
- return {'url': url, 'method': method, 'body': body, 'headers': headers}
1677
-
1678
- def parse_transaction_status(self, status):
1679
- statuses = {
1680
- 'processing': 'pending',
1681
- 'checking by system': 'pending',
1682
- 'hodl': 'pending',
1683
- 'amount too low': 'failed',
1684
- 'not confirmed': 'pending',
1685
- 'cancelled by user': 'canceled',
1686
- 'approved': 'pending',
1687
- 'finished': 'ok',
1688
- 'withdrawal error': 'failed',
1689
- 'deposit error': 'failed',
1690
- 'cancelled by admin': 'canceled',
1691
- 'awaiting': 'pending',
1692
- }
1693
- return self.safe_string(statuses, status, status)
1694
-
1695
- def parse_transaction(self, transaction, currency=None):
1696
- #
1697
- # fetchDeposit & fetchDeposits
1698
- #
1699
- # {
1700
- # "id": 123654789,
1701
- # "currency_id": 1,
1702
- # "currency_code": "BTC",
1703
- # "deposit_fee_currency_id": 1,
1704
- # "deposit_fee_currency_code": "BTC",
1705
- # "amount": 0.25,
1706
- # "fee": 0.00025,
1707
- # "txid": "qwertyuhgfdsasdfgh",
1708
- # "protocol_id": 0,
1709
- # "deposit_status_id": 1,
1710
- # "status": "PROCESSING",
1711
- # "status_color": "#BC3D51",
1712
- # "created_at": "2018-11-28 12:32:08",
1713
- # "timestamp": "1543409389",
1714
- # "confirmations": "1 of 2"
1715
- # }
1716
- #
1717
- # fetchWithdrawal and fetchWithdrawals
1718
- #
1719
- # {
1720
- # "id": 65899,
1721
- # "amount": "0.00600000",
1722
- # "currency_id": 1,
1723
- # "currency_code": "BTC",
1724
- # "fee": "0.00400000",
1725
- # "fee_currency_id": 1,
1726
- # "fee_currency_code": "BTC",
1727
- # "withdrawal_status_id": 1,
1728
- # "status": "Not Confirmed",
1729
- # "status_color": "#BC3D51",
1730
- # "created_at": "2019-01-21 09:36:05",
1731
- # "created_ts": "1548063365",
1732
- # "updated_at": "2019-01-21 09:36:05",
1733
- # "updated_ts": "1548063365",
1734
- # "txid": null,
1735
- # "protocol_id": 0,
1736
- # "withdrawal_address": {
1737
- # "address": "0X12WERTYUIIJHGFVBNMJHGDFGHJ765SDFGHJ",
1738
- # "address_name": "Address",
1739
- # "additional_address_parameter": "qwertyuiopasdfghjkl",
1740
- # "additional_address_parameter_name": "Destination Tag",
1741
- # "notification": "",
1742
- # "protocol_id": 10,
1743
- # "protocol_name": "Tether OMNI",
1744
- # "supports_new_address_creation": False
1745
- # }
1746
- # }
1747
- #
1748
- id = self.safe_string(transaction, 'id')
1749
- withdrawalAddress = self.safe_value(transaction, 'withdrawal_address', {})
1750
- address = self.safe_string(withdrawalAddress, 'address')
1751
- tag = self.safe_string(withdrawalAddress, 'additional_address_parameter')
1752
- currencyId = self.safe_string(transaction, 'currency_id')
1753
- code = None
1754
- if currencyId in self.currencies_by_id:
1755
- currency = self.currencies_by_id[currencyId]
1756
- else:
1757
- code = self.common_currency_code(self.safe_string(transaction, 'currency_code'))
1758
- if (code is None) and (currency is not None):
1759
- code = currency['code']
1760
- type = 'deposit' if ('deposit_status_id' in transaction) else 'withdrawal'
1761
- amount = self.safe_number(transaction, 'amount')
1762
- status = self.parse_transaction_status(self.safe_string_lower(transaction, 'status'))
1763
- timestamp = self.safe_timestamp_2(transaction, 'timestamp', 'created_ts')
1764
- updated = self.safe_timestamp(transaction, 'updated_ts')
1765
- txid = self.safe_string(transaction, 'txid')
1766
- fee = None
1767
- feeCost = self.safe_number(transaction, 'fee')
1768
- if feeCost is not None:
1769
- feeCurrencyId = self.safe_string_2(transaction, 'fee_currency_id', 'deposit_fee_currency_id')
1770
- feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
1771
- fee = {
1772
- 'cost': feeCost,
1773
- 'currency': feeCurrencyCode,
1774
- }
1775
- network = self.safe_string(withdrawalAddress, 'protocol_name')
1776
- return {
1777
- 'info': transaction,
1778
- 'id': id,
1779
- 'txid': txid,
1780
- 'timestamp': timestamp,
1781
- 'datetime': self.iso8601(timestamp),
1782
- 'network': network,
1783
- 'addressFrom': None,
1784
- 'address': address,
1785
- 'addressTo': address,
1786
- 'tagFrom': None,
1787
- 'tag': tag,
1788
- 'tagTo': tag,
1789
- 'type': type,
1790
- 'amount': amount,
1791
- 'currency': code,
1792
- 'status': status,
1793
- 'updated': updated,
1794
- 'fee': fee,
1795
- }
1796
-
1797
- def fetch_deposit(self, id: str, code: Optional[str] = None, params={}):
1798
- """
1799
- see https://apidocs.stex.com/#tag/Profile/paths/~1profile~1deposits~1{id}/get
1800
- fetch information on a deposit
1801
- :param str id: deposit id
1802
- :param str|None code: not used by stex fetchDeposit()
1803
- :param dict params: extra parameters specific to the stex api endpoint
1804
- :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
1805
- """
1806
- self.load_markets()
1807
- request = {
1808
- 'id': id,
1809
- }
1810
- response = self.profileGetDepositsId(self.extend(request, params))
1811
- #
1812
- # {
1813
- # success: True,
1814
- # data: {
1815
- # id: '21974074',
1816
- # currency_id: '272',
1817
- # block_explorer_url: 'https://omniexplorer.info/search/',
1818
- # currency_code: 'USDT',
1819
- # deposit_fee_currency_id: '272',
1820
- # deposit_fee_currency_code: 'USDT',
1821
- # amount: '11.00000000',
1822
- # fee: '0.00000000',
1823
- # deposit_status_id: '3',
1824
- # status: 'FINISHED',
1825
- # status_color: '#00BE75',
1826
- # txid: '15b50da4600a5021dbddaed8f4a71de093bf206ea66eb4ab2f151e3e9e2fed71',
1827
- # protocol_id: '24',
1828
- # confirmations: '129 of 20',
1829
- # created_at: '2022-05-16 16:38:40',
1830
- # timestamp: '1652719120',
1831
- # protocol_specific_settings: [{
1832
- # protocol_name: 'TRON',
1833
- # protocol_id: '24',
1834
- # block_explorer_url: 'https://tronscan.org/#/transaction/'
1835
- # }]
1836
- # },
1837
- # unified_message: {
1838
- # message_id: 'operation_successful',
1839
- # substitutions: []
1840
- # }
1841
- # }
1842
- #
1843
- data = self.safe_value(response, 'data', {})
1844
- return self.parse_transaction(data)
1845
-
1846
- def fetch_deposits(self, code: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
1847
- """
1848
- see https://apidocs.stex.com/#tag/Profile/paths/~1profile~1deposits/get
1849
- fetch all deposits made to an account
1850
- :param str|None code: unified currency code
1851
- :param int|None since: the earliest time in ms to fetch deposits for
1852
- :param int|None limit: the maximum number of deposits structures to retrieve
1853
- :param dict params: extra parameters specific to the stex api endpoint
1854
- :returns [dict]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
1855
- """
1856
- self.load_markets()
1857
- currency = None
1858
- request = {}
1859
- if code is not None:
1860
- currency = self.currency(code)
1861
- request['currencyId'] = currency['id']
1862
- if limit is not None:
1863
- request['limit'] = limit
1864
- if since is not None:
1865
- request['timeStart'] = since
1866
- response = self.profileGetDeposits(self.extend(request, params))
1867
- #
1868
- # {
1869
- # "success": True,
1870
- # "data": [
1871
- # {
1872
- # "id": 123654789,
1873
- # "currency_id": 1,
1874
- # "currency_code": "BTC",
1875
- # "deposit_fee_currency_id": 1,
1876
- # "deposit_fee_currency_code": "BTC",
1877
- # "amount": 0.25,
1878
- # "fee": 0.00025,
1879
- # "txid": "qwertyuhgfdsasdfgh",
1880
- # "protocol_id": 0,
1881
- # "deposit_status_id": 1,
1882
- # "status": "PROCESSING",
1883
- # "status_color": "#BC3D51",
1884
- # "created_at": "2018-11-28 12:32:08",
1885
- # "timestamp": "1543409389",
1886
- # "confirmations": "1 of 2",
1887
- # "protocol_specific_settings": {
1888
- # "protocol_name": "Tether OMNI",
1889
- # "protocol_id": 10,
1890
- # "block_explorer_url": "https://omniexplorer.info/search/"
1891
- # }
1892
- # }
1893
- # ]
1894
- # }
1895
- #
1896
- deposits = self.safe_value(response, 'data', [])
1897
- return self.parse_transactions(deposits, currency, since, limit)
1898
-
1899
- def fetch_withdrawal(self, id: str, code: Optional[str] = None, params={}):
1900
- """
1901
- see https://apidocs.stex.com/#tag/Profile/paths/~1profile~1withdrawals~1{id}/get
1902
- fetch data on a currency withdrawal via the withdrawal id
1903
- :param str id: withdrawal id
1904
- :param str|None code: not used by stex.fetchWithdrawal
1905
- :param dict params: extra parameters specific to the stex api endpoint
1906
- :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
1907
- """
1908
- self.load_markets()
1909
- request = {
1910
- 'id': id,
1911
- }
1912
- response = self.profileGetWithdrawalsId(self.extend(request, params))
1913
- #
1914
- # {
1915
- # "success": True,
1916
- # "data": {
1917
- # "id": 65899,
1918
- # "amount": "0.00600000",
1919
- # "currency_id": 1,
1920
- # "currency_code": "BTC",
1921
- # "fee": "0.00400000",
1922
- # "fee_currency_id": 1,
1923
- # "fee_currency_code": "BTC",
1924
- # "withdrawal_status_id": 1,
1925
- # "status": "Not Confirmed",
1926
- # "status_color": "#BC3D51",
1927
- # "created_at": "2019-01-21 09:36:05",
1928
- # "created_ts": "1548063365",
1929
- # "updated_at": "2019-01-21 09:36:05",
1930
- # "updated_ts": "1548063365",
1931
- # "reason": "string",
1932
- # "txid": null,
1933
- # "protocol_id": 0,
1934
- # "withdrawal_address": {
1935
- # "address": "0X12WERTYUIIJHGFVBNMJHGDFGHJ765SDFGHJ",
1936
- # "address_name": "Address",
1937
- # "additional_address_parameter": "qwertyuiopasdfghjkl",
1938
- # "additional_address_parameter_name": "Destination Tag",
1939
- # "notification": "",
1940
- # "protocol_id": 10,
1941
- # "protocol_name": "Tether OMNI",
1942
- # "supports_new_address_creation": False
1943
- # },
1944
- # "protocol_specific_settings": {
1945
- # "protocol_name": "Tether OMNI",
1946
- # "protocol_id": 10,
1947
- # "block_explorer_url": "https://omniexplorer.info/search/"
1948
- # }
1949
- # }
1950
- # }
1951
- #
1952
- data = self.safe_value(response, 'data', {})
1953
- return self.parse_transaction(data)
1954
-
1955
- def fetch_withdrawals(self, code: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
1956
- """
1957
- see https://apidocs.stex.com/#tag/Profile/paths/~1profile~1withdrawals/get
1958
- fetch all withdrawals made from an account
1959
- :param str|None code: unified currency code
1960
- :param int|None since: the earliest time in ms to fetch withdrawals for
1961
- :param int|None limit: the maximum number of withdrawals structures to retrieve
1962
- :param dict params: extra parameters specific to the stex api endpoint
1963
- :returns [dict]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
1964
- """
1965
- self.load_markets()
1966
- currency = None
1967
- request = {}
1968
- if code is not None:
1969
- currency = self.currency(code)
1970
- request['currencyId'] = currency['id']
1971
- if limit is not None:
1972
- request['limit'] = limit
1973
- if since is not None:
1974
- request['timeStart'] = since
1975
- response = self.profileGetWithdrawals(self.extend(request, params))
1976
- #
1977
- # {
1978
- # "success": True,
1979
- # "data": [
1980
- # {
1981
- # "id": 65899,
1982
- # "amount": "0.00600000",
1983
- # "currency_id": 1,
1984
- # "currency_code": "BTC",
1985
- # "fee": "0.00400000",
1986
- # "fee_currency_id": 1,
1987
- # "fee_currency_code": "BTC",
1988
- # "withdrawal_status_id": 1,
1989
- # "status": "Not Confirmed",
1990
- # "status_color": "#BC3D51",
1991
- # "created_at": "2019-01-21 09:36:05",
1992
- # "created_ts": "1548063365",
1993
- # "updated_at": "2019-01-21 09:36:05",
1994
- # "updated_ts": "1548063365",
1995
- # "txid": null,
1996
- # "protocol_id": 0,
1997
- # "withdrawal_address": {
1998
- # "address": "0X12WERTYUIIJHGFVBNMJHGDFGHJ765SDFGHJ",
1999
- # "address_name": "Address",
2000
- # "additional_address_parameter": "qwertyuiopasdfghjkl",
2001
- # "additional_address_parameter_name": "Destination Tag",
2002
- # "notification": "",
2003
- # "protocol_id": 10,
2004
- # "protocol_name": "Tether OMNI",
2005
- # "supports_new_address_creation": False
2006
- # },
2007
- # "protocol_specific_settings": {
2008
- # "protocol_name": "Tether OMNI",
2009
- # "protocol_id": 10,
2010
- # "block_explorer_url": "https://omniexplorer.info/search/"
2011
- # }
2012
- # }
2013
- # ]
2014
- # }
2015
- #
2016
- withdrawals = self.safe_value(response, 'data', [])
2017
- return self.parse_transactions(withdrawals, currency, since, limit)
2018
-
2019
- def transfer(self, code: str, amount, fromAccount, toAccount, params={}):
2020
- """
2021
- see https://apidocs.stex.com/#tag/Profile/paths/~1profile~1referral~1bonus_transfer~1{currencyId}/post
2022
- see https://apidocs.stex.com/#tag/Profile/paths/~1profile~1wallets~1{walletId}~1hold_amount/post
2023
- transfer currency internally between wallets on the same account
2024
- :param str code: unified currency code
2025
- :param float amount: amount to transfer
2026
- :param str fromAccount: account to transfer from
2027
- :param str toAccount: account to transfer to
2028
- :param dict params: extra parameters specific to the stex api endpoint
2029
- :returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
2030
- """
2031
- self.load_markets()
2032
- currency = self.currency(code)
2033
- method = None
2034
- request = {}
2035
- if fromAccount == 'referal' and toAccount == 'spot':
2036
- request['currencyId'] = currency['id']
2037
- method = 'profilePostReferralBonusTransferCurrencyId'
2038
- elif toAccount == 'hold':
2039
- request['walletId'] = fromAccount
2040
- amount = self.currency_to_precision(code, amount)
2041
- amount = Precise.string_neg(amount)
2042
- request['amount'] = amount
2043
- method = 'profilePostWalletsWalletIdHoldAmount'
2044
- elif fromAccount == 'hold':
2045
- request['walletId'] = toAccount
2046
- request['amount'] = amount
2047
- method = 'profilePostWalletsWalletIdHoldAmount'
2048
- else:
2049
- raise ExchangeError(self.id + ' transfer() only allows transfers of referal to spot and between a walletId and funding')
2050
- response = getattr(self, method)(self.extend(request, params))
2051
- #
2052
- # profilePostReferralBonusTransferCurrencyId
2053
- # {
2054
- # "success": True,
2055
- # "data": ""
2056
- # }
2057
- #
2058
- # profilePostWalletsWalletIdHoldAmount
2059
- # {
2060
- # success: True,
2061
- # data: {
2062
- # id: '4055802',
2063
- # currency_id: '272',
2064
- # currency_code: 'USDT',
2065
- # currency_name: 'TetherUSD',
2066
- # balance: '10.00000000',
2067
- # frozen_balance: '0.00000000',
2068
- # bonus_balance: '0.00000000',
2069
- # hold_balance: '1.00000000',
2070
- # total_balance: '11.00000000',
2071
- # disable_deposits: False,
2072
- # disable_withdrawals: False,
2073
- # withdrawal_limit: '0.00000000',
2074
- # delisted: False,
2075
- # disabled: False,
2076
- # deposit_address: null,
2077
- # multi_deposit_addresses: [{
2078
- # address: 'TYzhabfHWMLgLnMW46ZyUHkUVJPXaDgdxK',
2079
- # address_name: 'Deposit Address',
2080
- # additional_address_parameter: null,
2081
- # additional_address_parameter_name: null,
2082
- # notification: '',
2083
- # protocol_id: '24',
2084
- # protocol_name: 'TRON',
2085
- # supports_new_address_creation: False
2086
- # }],
2087
- # contract_or_asset_id: '31',
2088
- # contract_field_name: null,
2089
- # withdrawal_additional_field_name: null,
2090
- # depo_message: '',
2091
- # wd_message: '',
2092
- # currency_type_id: '23',
2093
- # protocol_specific_settings: [{
2094
- # {
2095
- # protocol_name: 'ERC20',
2096
- # protocol_id: '5',
2097
- # active: True,
2098
- # disable_deposits: False,
2099
- # disable_withdrawals: False,
2100
- # withdrawal_limit: '0',
2101
- # deposit_fee_currency_id: '272',
2102
- # deposit_fee_currency_code: 'USDT',
2103
- # deposit_fee_percent: '0',
2104
- # deposit_fee_const: '0',
2105
- # withdrawal_fee_currency_id: '272',
2106
- # withdrawal_fee_currency_code: 'USDT',
2107
- # withdrawal_fee_const: '10',
2108
- # withdrawal_fee_percent: '0',
2109
- # block_explorer_url: 'https://etherscan.io/tx/',
2110
- # contract_or_asset_id: '0xdac17f958d2ee523a2206206994597c13d831ec7',
2111
- # contract_field_name: '',
2112
- # withdrawal_additional_field_name: '',
2113
- # depo_message: '',
2114
- # wd_message: ''
2115
- # },
2116
- # ...
2117
- # ],
2118
- # coin_info: {
2119
- # twitter: 'https://twitter.com/Tether_to',
2120
- # version: '',
2121
- # facebook: 'https://www.facebook.com/tether.to',
2122
- # telegram: '',
2123
- # icon_large: 'https://app-coin-images.stex.com/large/usdt.png',
2124
- # icon_small: 'https://app-coin-images.stex.com/small/usdt.png',
2125
- # description: 'Tether(USDT) is a cryptocurrency with a value meant to mirror the value of the U.S. dollar. The idea was to create a stable cryptocurrency that can be used like digital dollars. Coins that serve self purpose of being a stable dollar substitute are called “stable coins.” Tether is the most popular stable coin and even acts dollar replacement on many popular exchanges! According to their site, Tether converts cash into digital currency, to anchor or “tether” the value of the coin to the price of national currencies like the US dollar, the Euro, and the Yen. Like other cryptos it uses blockchain. Unlike other cryptos, it is [according to the official Tether site] “100% backed by USD”(USD is held in reserve). The primary use of Tether is that it offers some stability to the otherwise volatile crypto space and offers liquidity to exchanges who can’t deal in dollars and with banks(for example to the sometimes controversial but leading exchange Bitfinex).The digital coins are issued by a company called Tether Limited that is governed by the laws of the British Virgin Islands, according to the legal part of its website. It is incorporated in Hong Kong. It has emerged that Jan Ludovicus van der Velde is the CEO of cryptocurrency exchange Bitfinex, which has been accused of being involved in the price manipulation of bitcoin,. Many people trading on exchanges, including Bitfinex, will use tether to buy other cryptocurrencies like bitcoin. Tether Limited argues that using self method to buy virtual currencies allows users to move fiat in and out of an exchange more quickly and cheaply. Also, exchanges typically have rocky relationships with banks, and using Tether is a way to circumvent that.USDT is fairly simple to use. Once on exchanges like Poloniex or Bittrex, it can be used to purchase Bitcoin and other cryptocurrencies. It can be easily transferred from an exchange to any Omni Layer enabled wallet. Tether has no transaction fees, although external wallets and exchanges may charge one. In order to convert USDT to USD and vise versa through the Tether.to Platform, users must pay a small fee. Buying and selling Tether for Bitcoin can be done through a variety of exchanges like the ones mentioned previously or through the Tether.to platform, which also allows the conversion between USD to and from your bank account.',
2126
- # official_site: 'https://tether.to/',
2127
- # official_block_explorer: 'https://etherscan.io/token/0xdac17f958d2ee523a2206206994597c13d831ec7'
2128
- # },
2129
- # rates: {
2130
- # BTC: '0.00003372',
2131
- # USD: '1'
2132
- # }
2133
- # },
2134
- # unified_message: {
2135
- # message_id: 'operation_successful',
2136
- # substitutions: []
2137
- # }
2138
- # }
2139
- #
2140
- data = self.safe_value(response, 'data', {})
2141
- transfer = self.parse_transfer(data, currency)
2142
- transferOptions = self.safe_value(self.options, 'transfer', {})
2143
- fillResponseFromRequest = self.safe_value(transferOptions, 'fillResponseFromRequest', True)
2144
- if fillResponseFromRequest:
2145
- transfer['fromAccount'] = fromAccount
2146
- transfer['toAccount'] = toAccount
2147
- if isinstance(amount, str) and Precise.string_lt(amount, '0'):
2148
- amount = self.parse_number(Precise.string_neg(amount))
2149
- transfer['amount'] = amount
2150
- if transfer['currency'] is None:
2151
- transfer['currency'] = code
2152
- return transfer
2153
-
2154
- def parse_transfer(self, transfer, currency=None):
2155
- #
2156
- # {
2157
- # "id": 45875,
2158
- # "currency_id": 1,
2159
- # "currency_code": "USDT",
2160
- # "currency_name": "TetherUSD",
2161
- # "balance": "0.198752",
2162
- # "frozen_balance": "1.5784",
2163
- # "bonus_balance": "0.000",
2164
- # "hold_balance": "0.000",
2165
- # "total_balance": "1.777152",
2166
- # "disable_deposits": False,
2167
- # "disable_withdrawals": False,
2168
- # "withdrawal_limit": "string",
2169
- # "delisted": False,
2170
- # "disabled": False,
2171
- # "deposit_address": {
2172
- # "address": "0X12WERTYUIIJHGFVBNMJHGDFGHJ765SDFGHJ",
2173
- # "address_name": "Address",
2174
- # "additional_address_parameter": "qwertyuiopasdfghjkl",
2175
- # "additional_address_parameter_name": "Destination Tag",
2176
- # "notification": "",
2177
- # "protocol_id": 10,
2178
- # "protocol_name": "Tether OMNI",
2179
- # "supports_new_address_creation": False
2180
- # },
2181
- # "multi_deposit_addresses": [{
2182
- # "address": "0X12WERTYUIIJHGFVBNMJHGDFGHJ765SDFGHJ",
2183
- # "address_name": "Address",
2184
- # "additional_address_parameter": "qwertyuiopasdfghjkl",
2185
- # "additional_address_parameter_name": "Destination Tag",
2186
- # "notification": "",
2187
- # "protocol_id": 10,
2188
- # "protocol_name": "Tether OMNI",
2189
- # "supports_new_address_creation": False
2190
- # }],
2191
- # "withdrawal_additional_field_name": "Payment ID(optional)",
2192
- # "currency_type_id": 23,
2193
- # "protocol_specific_settings": [{
2194
- # "protocol_name": "Tether OMNI",
2195
- # "protocol_id": 10,
2196
- # "active": True,
2197
- # "disable_deposits": False,
2198
- # "disable_withdrawals": False,
2199
- # "withdrawal_limit": 0,
2200
- # "deposit_fee_currency_id": 272,
2201
- # "deposit_fee_currency_code": "USDT",
2202
- # "deposit_fee_percent": 0,
2203
- # "deposit_fee_const": 0,
2204
- # "withdrawal_fee_currency_id": 1,
2205
- # "withdrawal_fee_currency_code": "USDT",
2206
- # "withdrawal_fee_const": 0.002,
2207
- # "withdrawal_fee_percent": 0,
2208
- # "block_explorer_url": "https://omniexplorer.info/search/",
2209
- # "withdrawal_additional_field_name": ""
2210
- # }],
2211
- # "coin_info": {
2212
- # "twitter": "https://twitter.com/btc",
2213
- # "version": "",
2214
- # "facebook": "https://www.facebook.com/bitcoins",
2215
- # "telegram": "",
2216
- # "icon_large": "https://app-coin-images.stex.com/large/btc.png",
2217
- # "icon_small": "https://app-coin-images.stex.com/small/btc.png",
2218
- # "description": "Bitcoin is the first successful internet money based on peer-to-peer technology;....",
2219
- # "official_site": "http://www.bitcoin.org",
2220
- # "official_block_explorer": "https://blockchair.com/bitcoin/"
2221
- # },
2222
- # "rates": {
2223
- # "BTC": 0.000001
2224
- # }
2225
- # }
2226
- #
2227
- currencyId = self.safe_string(transfer, 'currency_id')
2228
- code = None
2229
- if currencyId in self.currencies_by_id:
2230
- currency = self.currencies_by_id[currencyId]
2231
- else:
2232
- code = self.common_currency_code(self.safe_string(transfer, 'currency_code'))
2233
- if code is None:
2234
- code = self.safe_value(currency, 'code')
2235
- return {
2236
- 'info': transfer,
2237
- 'id': self.safe_string(transfer, 'id'),
2238
- 'timestamp': None,
2239
- 'datetime': None,
2240
- 'currency': code,
2241
- 'amount': None,
2242
- 'fromAccount': None,
2243
- 'toAccount': None,
2244
- 'status': None,
2245
- }
2246
-
2247
- def withdraw(self, code: str, amount, address, tag=None, params={}):
2248
- """
2249
- see https://apidocs.stex.com/#tag/Profile/paths/~1profile~1withdraw/post
2250
- make a withdrawal
2251
- :param str code: unified currency code
2252
- :param float amount: the amount to withdraw
2253
- :param str address: the address to withdraw to
2254
- :param str|None tag:
2255
- :param dict params: extra parameters specific to the stex api endpoint
2256
- :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
2257
- """
2258
- tag, params = self.handle_withdraw_tag_and_params(tag, params)
2259
- self.check_address(address)
2260
- self.load_markets()
2261
- currency = self.currency(code)
2262
- request = {
2263
- 'currency_id': currency['id'],
2264
- 'amount': float(self.currency_to_precision(code, amount)),
2265
- 'address': address,
2266
- # 'protocol_id': 10, # optional, to be used with multicurrency wallets like USDT
2267
- # 'additional_address_parameter': tag, # optional
2268
- }
2269
- if tag is not None:
2270
- request['additional_address_parameter'] = tag
2271
- networks = self.safe_value(self.options, 'networks', {})
2272
- networkRaw = self.safe_string_upper(params, 'network') # self line allows the user to specify either ERC20 or ETH
2273
- network = self.safe_integer(networks, networkRaw, self.parse_to_int(networkRaw)) # handle ERC20>ETH alias
2274
- if network is not None:
2275
- request['protocol_id'] = network
2276
- params = self.omit(params, 'network')
2277
- response = self.profilePostWithdraw(self.extend(request, params))
2278
- #
2279
- # {
2280
- # "success": True,
2281
- # "data": {
2282
- # "id": 65899,
2283
- # "amount": "0.00600000",
2284
- # "currency_id": 1,
2285
- # "currency_code": "BTC",
2286
- # "fee": "0.00400000",
2287
- # "fee_currency_id": 1,
2288
- # "fee_currency_code": "BTC",
2289
- # "withdrawal_status_id": 1,
2290
- # "status": "Not Confirmed",
2291
- # "status_color": "#BC3D51",
2292
- # "created_at": "2019-01-21 09:36:05",
2293
- # "created_ts": "1548063365",
2294
- # "updated_at": "2019-01-21 09:36:05",
2295
- # "updated_ts": "1548063365",
2296
- # "txid": null,
2297
- # "protocol_id": 0,
2298
- # "withdrawal_address": {
2299
- # "address": "0X12WERTYUIIJHGFVBNMJHGDFGHJ765SDFGHJ",
2300
- # "address_name": "Address",
2301
- # "additional_address_parameter": "qwertyuiopasdfghjkl",
2302
- # "additional_address_parameter_name": "Destination Tag",
2303
- # "notification": "",
2304
- # "protocol_id": 10,
2305
- # "protocol_name": "Tether OMNI",
2306
- # "supports_new_address_creation": False
2307
- # }
2308
- # }
2309
- # }
2310
- #
2311
- data = self.safe_value(response, 'data', {})
2312
- return self.parse_transaction(data, currency)
2313
-
2314
- def fetch_transaction_fees(self, codes=None, params={}):
2315
- """
2316
- *DEPRECATED* please use fetchDepositWithdrawFees instead
2317
- see https://apidocs.stex.com/#tag/Public/paths/~1public~1currencies/get
2318
- :param [str]|None codes: list of unified currency codes
2319
- :param dict params: extra parameters specific to the stex api endpoint
2320
- :returns dict: a list of `fee structures <https://docs.ccxt.com/#/?id=fee-structure>`
2321
- """
2322
- self.load_markets()
2323
- #
2324
- # {
2325
- # "success": True,
2326
- # "data": [
2327
- # {
2328
- # "id": 1,
2329
- # "code": "BTC",
2330
- # "name": "Bitcoin",
2331
- # "active": True,
2332
- # "delisted": False,
2333
- # "precision": 8,
2334
- # "minimum_tx_confirmations": 24,
2335
- # "minimum_withdrawal_amount": "0.009",
2336
- # "minimum_deposit_amount": "0.000003",
2337
- # "deposit_fee_currency_id": 1,
2338
- # "deposit_fee_currency_code": "ETH",
2339
- # "deposit_fee_const": "0.00001",
2340
- # "deposit_fee_percent": "0",
2341
- # "withdrawal_fee_currency_id": 1,
2342
- # "withdrawal_fee_currency_code": "ETH",
2343
- # "withdrawal_fee_const": "0.0015",
2344
- # "withdrawal_fee_percent": "0",
2345
- # "withdrawal_limit": "string",
2346
- # "block_explorer_url": "https://blockchain.info/tx/",
2347
- # "protocol_specific_settings": [
2348
- # {
2349
- # "protocol_name": "Tether OMNI",
2350
- # "protocol_id": 10,
2351
- # "active": True,
2352
- # "withdrawal_fee_currency_id": 1,
2353
- # "withdrawal_fee_const": 0.002,
2354
- # "withdrawal_fee_percent": 0,
2355
- # "block_explorer_url": "https://omniexplorer.info/search/"
2356
- # }
2357
- # ]
2358
- # }
2359
- # ]
2360
- # }
2361
- #
2362
- currencyKeys = list(self.currencies.keys())
2363
- result = {}
2364
- for i in range(0, len(currencyKeys)):
2365
- code = currencyKeys[i]
2366
- currency = self.currencies[code]
2367
- if codes is not None and not self.in_array(code, codes):
2368
- continue
2369
- info = self.safe_value(currency, 'info')
2370
- result[code] = {
2371
- 'withdraw': self.safe_number(currency, 'fee'),
2372
- 'deposit': self.safe_number(info, 'deposit_fee_const'),
2373
- 'info': info,
2374
- }
2375
- return result
2376
-
2377
- def fetch_deposit_withdraw_fees(self, codes=None, params={}):
2378
- """
2379
- fetch deposit and withdraw fees
2380
- see https://apidocs.stex.com/#tag/Public/paths/~1public~1currencies/get
2381
- :param [str]|None codes: list of unified currency codes
2382
- :param dict params: extra parameters specific to the stex api endpoint
2383
- :returns dict: a list of `fee structures <https://docs.ccxt.com/#/?id=fee-structure>`
2384
- """
2385
- self.load_markets()
2386
- response = self.publicGetCurrencies(params)
2387
- #
2388
- # {
2389
- # "success": True,
2390
- # "data": [
2391
- # {
2392
- # "id": 1,
2393
- # "code": "BTC",
2394
- # "name": "Bitcoin",
2395
- # "active": True,
2396
- # "delisted": False,
2397
- # "precision": 8,
2398
- # "minimum_tx_confirmations": 24,
2399
- # "minimum_withdrawal_amount": "0.009",
2400
- # "minimum_deposit_amount": "0.000003",
2401
- # "deposit_fee_currency_id": 1,
2402
- # "deposit_fee_currency_code": "ETH",
2403
- # "deposit_fee_const": "0.00001",
2404
- # "deposit_fee_percent": "0",
2405
- # "withdrawal_fee_currency_id": 1,
2406
- # "withdrawal_fee_currency_code": "ETH",
2407
- # "withdrawal_fee_const": "0.0015",
2408
- # "withdrawal_fee_percent": "0",
2409
- # "withdrawal_limit": "string",
2410
- # "block_explorer_url": "https://blockchain.info/tx/",
2411
- # "protocol_specific_settings": [
2412
- # {
2413
- # "protocol_name": "Tether OMNI",
2414
- # "protocol_id": 10,
2415
- # "active": True,
2416
- # "withdrawal_fee_currency_id": 1,
2417
- # "withdrawal_fee_const": 0.002,
2418
- # "withdrawal_fee_percent": 0,
2419
- # "block_explorer_url": "https://omniexplorer.info/search/"
2420
- # }
2421
- # ]
2422
- # }
2423
- # ...
2424
- # ]
2425
- # }
2426
- #
2427
- data = self.safe_value(response, 'data')
2428
- return self.parse_deposit_withdraw_fees(data, codes, 'code')
2429
-
2430
- def parse_deposit_withdraw_fee(self, fee, currency=None):
2431
- #
2432
- # {
2433
- # "id": 1,
2434
- # "code": "BTC",
2435
- # "name": "Bitcoin",
2436
- # "active": True,
2437
- # "delisted": False,
2438
- # "precision": 8,
2439
- # "minimum_tx_confirmations": 24,
2440
- # "minimum_withdrawal_amount": "0.009",
2441
- # "minimum_deposit_amount": "0.000003",
2442
- # "deposit_fee_currency_id": 1,
2443
- # "deposit_fee_currency_code": "ETH",
2444
- # "deposit_fee_const": "0.00001",
2445
- # "deposit_fee_percent": "0",
2446
- # "withdrawal_fee_currency_id": 1,
2447
- # "withdrawal_fee_currency_code": "ETH",
2448
- # "withdrawal_fee_const": "0.0015",
2449
- # "withdrawal_fee_percent": "0",
2450
- # "withdrawal_limit": "string",
2451
- # "block_explorer_url": "https://blockchain.info/tx/",
2452
- # "protocol_specific_settings": [
2453
- # {
2454
- # "protocol_name": "Tether OMNI",
2455
- # "protocol_id": 10,
2456
- # "active": True,
2457
- # "withdrawal_fee_currency_id": 1,
2458
- # "withdrawal_fee_const": 0.002,
2459
- # "withdrawal_fee_percent": 0,
2460
- # "block_explorer_url": "https://omniexplorer.info/search/"
2461
- # }
2462
- # ]
2463
- # }
2464
- #
2465
- result = {
2466
- 'withdraw': {
2467
- 'fee': self.safe_number(fee, 'withdrawal_fee_const'),
2468
- 'percentage': False,
2469
- },
2470
- 'deposit': {
2471
- 'fee': self.safe_number(fee, 'deposit_fee_const'),
2472
- 'percentage': False,
2473
- },
2474
- 'networks': {},
2475
- }
2476
- networks = self.safe_value(fee, 'protocol_specific_settings', [])
2477
- for i in range(0, len(networks)):
2478
- network = networks[i]
2479
- networkId = self.safe_string(network, 'protocol_name')
2480
- networkCode = self.network_id_to_code(networkId)
2481
- result['networks'][networkCode] = {
2482
- 'withdraw': {
2483
- 'fee': self.safe_number(network, 'withdrawal_fee_const'),
2484
- 'percentage': False,
2485
- },
2486
- 'deposit': {
2487
- 'fee': None,
2488
- 'percentage': None,
2489
- },
2490
- }
2491
- return result
2492
-
2493
- def handle_errors(self, httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody):
2494
- if response is None:
2495
- return None # fallback to default error handler
2496
- #
2497
- # {"success":false,"message":"Wrong parameters","errors":{"candleType":["Invalid Candle Type!"]}}
2498
- # {"success":false,"message":"Wrong parameters","errors":{"time":["timeStart or timeEnd is less then 1"]}}
2499
- # {"success":false,"message":"Not enough ETH"}
2500
- #
2501
- success = self.safe_value(response, 'success', False)
2502
- if not success:
2503
- message = self.safe_string(response, 'message')
2504
- feedback = self.id + ' ' + body
2505
- self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
2506
- self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
2507
- raise ExchangeError(feedback) # unknown message
2508
- return None