ccxt-ir 4.9.14__py2.py3-none-any.whl → 4.9.16__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/__init__.py +3 -1
- ccxt/abantether.py +2 -2
- ccxt/abstract/tehran_exchange.py +6 -0
- ccxt/abstract/toobit.py +1 -0
- ccxt/async_support/__init__.py +3 -1
- ccxt/async_support/abantether.py +2 -2
- ccxt/async_support/base/exchange.py +1 -1
- ccxt/async_support/hamtapay.py +4 -1
- ccxt/async_support/sarmayex.py +4 -3
- ccxt/async_support/tehran_exchange.py +317 -0
- ccxt/async_support/toobit.py +94 -43
- ccxt/base/exchange.py +1 -1
- ccxt/hamtapay.py +4 -1
- ccxt/pro/__init__.py +1 -1
- ccxt/sarmayex.py +4 -3
- ccxt/tehran_exchange.py +317 -0
- ccxt/toobit.py +94 -43
- {ccxt_ir-4.9.14.dist-info → ccxt_ir-4.9.16.dist-info}/METADATA +5 -5
- {ccxt_ir-4.9.14.dist-info → ccxt_ir-4.9.16.dist-info}/RECORD +22 -19
- {ccxt_ir-4.9.14.dist-info → ccxt_ir-4.9.16.dist-info}/WHEEL +0 -0
- {ccxt_ir-4.9.14.dist-info → ccxt_ir-4.9.16.dist-info}/licenses/LICENSE.txt +0 -0
- {ccxt_ir-4.9.14.dist-info → ccxt_ir-4.9.16.dist-info}/top_level.txt +0 -0
ccxt/__init__.py
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
# ----------------------------------------------------------------------------
|
|
24
24
|
|
|
25
|
-
__version__ = '4.9.
|
|
25
|
+
__version__ = '4.9.16'
|
|
26
26
|
|
|
27
27
|
# ----------------------------------------------------------------------------
|
|
28
28
|
|
|
@@ -210,6 +210,7 @@ from ccxt.ramzinex import ramzinex # noqa: F4
|
|
|
210
210
|
from ccxt.sarmayex import sarmayex # noqa: F401
|
|
211
211
|
from ccxt.sarrafex import sarrafex # noqa: F401
|
|
212
212
|
from ccxt.tabdeal import tabdeal # noqa: F401
|
|
213
|
+
from ccxt.tehran_exchange import tehran_exchange # noqa: F401
|
|
213
214
|
from ccxt.tetherland import tetherland # noqa: F401
|
|
214
215
|
from ccxt.timex import timex # noqa: F401
|
|
215
216
|
from ccxt.tokocrypto import tokocrypto # noqa: F401
|
|
@@ -356,6 +357,7 @@ exchanges = [
|
|
|
356
357
|
'sarmayex',
|
|
357
358
|
'sarrafex',
|
|
358
359
|
'tabdeal',
|
|
360
|
+
'tehran_exchange',
|
|
359
361
|
'tetherland',
|
|
360
362
|
'timex',
|
|
361
363
|
'tokocrypto',
|
ccxt/abantether.py
CHANGED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
from ccxt.base.types import Entry
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ImplicitAPI:
|
|
5
|
+
public_get_otc_v1_market_pair = publicGetOtcV1MarketPair = Entry('otc/v1/market/pair', 'public', 'GET', {'cost': 1})
|
|
6
|
+
public_get_otc_v1_market_order_pair_price = publicGetOtcV1MarketOrderPairPrice = Entry('otc/v1/market/order/pair/price', 'public', 'GET', {'cost': 1})
|
ccxt/abstract/toobit.py
CHANGED
|
@@ -4,3 +4,4 @@ from ccxt.base.types import Entry
|
|
|
4
4
|
class ImplicitAPI:
|
|
5
5
|
public_get_quote_v1_ticker_24hr = publicGetQuoteV1Ticker24hr = Entry('quote/v1/ticker/24hr', 'public', 'GET', {'cost': 1})
|
|
6
6
|
public_get_quote_v1_klines = publicGetQuoteV1Klines = Entry('quote/v1/klines', 'public', 'GET', {'cost': 1})
|
|
7
|
+
public_get_api_v1_exchangeinfo = publicGetApiV1ExchangeInfo = Entry('/api/v1/exchangeInfo', 'public', 'GET', {'cost': 1})
|
ccxt/async_support/__init__.py
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
# -----------------------------------------------------------------------------
|
|
6
6
|
|
|
7
|
-
__version__ = '4.9.
|
|
7
|
+
__version__ = '4.9.16'
|
|
8
8
|
|
|
9
9
|
# -----------------------------------------------------------------------------
|
|
10
10
|
|
|
@@ -190,6 +190,7 @@ from ccxt.async_support.ramzinex import ramzinex
|
|
|
190
190
|
from ccxt.async_support.sarmayex import sarmayex # noqa: F401
|
|
191
191
|
from ccxt.async_support.sarrafex import sarrafex # noqa: F401
|
|
192
192
|
from ccxt.async_support.tabdeal import tabdeal # noqa: F401
|
|
193
|
+
from ccxt.async_support.tehran_exchange import tehran_exchange # noqa: F401
|
|
193
194
|
from ccxt.async_support.tetherland import tetherland # noqa: F401
|
|
194
195
|
from ccxt.async_support.timex import timex # noqa: F401
|
|
195
196
|
from ccxt.async_support.tokocrypto import tokocrypto # noqa: F401
|
|
@@ -336,6 +337,7 @@ exchanges = [
|
|
|
336
337
|
'sarmayex',
|
|
337
338
|
'sarrafex',
|
|
338
339
|
'tabdeal',
|
|
340
|
+
'tehran_exchange',
|
|
339
341
|
'tetherland',
|
|
340
342
|
'timex',
|
|
341
343
|
'tokocrypto',
|
ccxt/async_support/abantether.py
CHANGED
ccxt/async_support/hamtapay.py
CHANGED
|
@@ -282,5 +282,8 @@ class hamtapay(Exchange, ImplicitAPI):
|
|
|
282
282
|
|
|
283
283
|
def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
|
|
284
284
|
url = self.urls['api']['public'] + '/' + path
|
|
285
|
-
headers = {
|
|
285
|
+
headers = {
|
|
286
|
+
'Content-Type': 'application/json',
|
|
287
|
+
'Origin': 'https://hamtapay.net',
|
|
288
|
+
}
|
|
286
289
|
return {'url': url, 'method': method, 'body': body, 'headers': headers}
|
ccxt/async_support/sarmayex.py
CHANGED
|
@@ -22,7 +22,7 @@ class sarmayex(Exchange, ImplicitAPI):
|
|
|
22
22
|
'pro': False,
|
|
23
23
|
'has': {
|
|
24
24
|
'CORS': None,
|
|
25
|
-
'spot':
|
|
25
|
+
'spot': False,
|
|
26
26
|
'margin': False,
|
|
27
27
|
'swap': False,
|
|
28
28
|
'future': False,
|
|
@@ -78,6 +78,7 @@ class sarmayex(Exchange, ImplicitAPI):
|
|
|
78
78
|
'fetchTradingFee': False,
|
|
79
79
|
'fetchTradingFees': False,
|
|
80
80
|
'fetchWithdrawals': False,
|
|
81
|
+
'otc': True,
|
|
81
82
|
'setLeverage': False,
|
|
82
83
|
'setMarginMode': False,
|
|
83
84
|
'transfer': False,
|
|
@@ -193,8 +194,8 @@ class sarmayex(Exchange, ImplicitAPI):
|
|
|
193
194
|
'baseId': baseId,
|
|
194
195
|
'quoteId': quoteId,
|
|
195
196
|
'settleId': None,
|
|
196
|
-
'type': '
|
|
197
|
-
'spot':
|
|
197
|
+
'type': 'otc',
|
|
198
|
+
'spot': False,
|
|
198
199
|
'margin': False,
|
|
199
200
|
'swap': False,
|
|
200
201
|
'future': False,
|
|
@@ -0,0 +1,317 @@
|
|
|
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.async_support.base.exchange import Exchange
|
|
7
|
+
from ccxt.abstract.tehran_exchange import ImplicitAPI
|
|
8
|
+
from ccxt.base.types import Any, Market, Strings, Ticker, Tickers
|
|
9
|
+
from typing import List
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class tehran_exchange(Exchange, ImplicitAPI):
|
|
13
|
+
|
|
14
|
+
def describe(self) -> Any:
|
|
15
|
+
return self.deep_extend(super(tehran_exchange, self).describe(), {
|
|
16
|
+
'id': 'tehran_exchange',
|
|
17
|
+
'name': 'Tehran Exchange',
|
|
18
|
+
'countries': ['IR'],
|
|
19
|
+
'rateLimit': 1000,
|
|
20
|
+
'version': '1',
|
|
21
|
+
'certified': False,
|
|
22
|
+
'pro': False,
|
|
23
|
+
'has': {
|
|
24
|
+
'CORS': None,
|
|
25
|
+
'spot': True,
|
|
26
|
+
'margin': False,
|
|
27
|
+
'swap': False,
|
|
28
|
+
'future': False,
|
|
29
|
+
'option': False,
|
|
30
|
+
'addMargin': False,
|
|
31
|
+
'cancelAllOrders': False,
|
|
32
|
+
'cancelOrder': False,
|
|
33
|
+
'cancelOrders': False,
|
|
34
|
+
'createDepositAddress': False,
|
|
35
|
+
'createOrder': False,
|
|
36
|
+
'createStopLimitOrder': False,
|
|
37
|
+
'createStopMarketOrder': False,
|
|
38
|
+
'createStopOrder': False,
|
|
39
|
+
'editOrder': False,
|
|
40
|
+
'fetchBalance': False,
|
|
41
|
+
'fetchBorrowInterest': False,
|
|
42
|
+
'fetchBorrowRateHistories': False,
|
|
43
|
+
'fetchBorrowRateHistory': False,
|
|
44
|
+
'fetchClosedOrders': False,
|
|
45
|
+
'fetchCrossBorrowRate': False,
|
|
46
|
+
'fetchCrossBorrowRates': False,
|
|
47
|
+
'fetchCurrencies': False,
|
|
48
|
+
'fetchDepositAddress': False,
|
|
49
|
+
'fetchDeposits': False,
|
|
50
|
+
'fetchFundingHistory': False,
|
|
51
|
+
'fetchFundingRate': False,
|
|
52
|
+
'fetchFundingRateHistory': False,
|
|
53
|
+
'fetchFundingRates': False,
|
|
54
|
+
'fetchIndexOHLCV': False,
|
|
55
|
+
'fetchIsolatedBorrowRate': False,
|
|
56
|
+
'fetchIsolatedBorrowRates': False,
|
|
57
|
+
'fetchL2OrderBook': False,
|
|
58
|
+
'fetchLedger': False,
|
|
59
|
+
'fetchLedgerEntry': False,
|
|
60
|
+
'fetchLeverageTiers': False,
|
|
61
|
+
'fetchMarkets': True,
|
|
62
|
+
'fetchMarkOHLCV': False,
|
|
63
|
+
'fetchMyTrades': False,
|
|
64
|
+
'fetchOHLCV': False,
|
|
65
|
+
'fetchOpenInterestHistory': False,
|
|
66
|
+
'fetchOpenOrders': False,
|
|
67
|
+
'fetchOrder': False,
|
|
68
|
+
'fetchOrderBook': False,
|
|
69
|
+
'fetchOrders': False,
|
|
70
|
+
'fetchOrderTrades': 'emulated',
|
|
71
|
+
'fetchPositions': False,
|
|
72
|
+
'fetchPremiumIndexOHLCV': False,
|
|
73
|
+
'fetchTicker': True,
|
|
74
|
+
'fetchTickers': True,
|
|
75
|
+
'fetchTime': False,
|
|
76
|
+
'fetchTrades': False,
|
|
77
|
+
'fetchTradingFee': False,
|
|
78
|
+
'fetchTradingFees': False,
|
|
79
|
+
'fetchWithdrawals': False,
|
|
80
|
+
'setLeverage': False,
|
|
81
|
+
'setMarginMode': False,
|
|
82
|
+
'transfer': False,
|
|
83
|
+
'withdraw': False,
|
|
84
|
+
},
|
|
85
|
+
'comment': 'This comment is optional',
|
|
86
|
+
'urls': {
|
|
87
|
+
'logo': 'https://cdn.arz.digital/cr-odin/img/exchanges/tehran_exchange/64x64.png',
|
|
88
|
+
'api': {
|
|
89
|
+
'public': 'https://otc-api.tehran.exchange',
|
|
90
|
+
},
|
|
91
|
+
'www': 'https://tehran.exchange',
|
|
92
|
+
'doc': [
|
|
93
|
+
'https://tehran.exchange',
|
|
94
|
+
],
|
|
95
|
+
},
|
|
96
|
+
'api': {
|
|
97
|
+
'public': {
|
|
98
|
+
'get': {
|
|
99
|
+
'otc/v1/market/pair': 1,
|
|
100
|
+
'otc/v1/market/order/pair/price': 1,
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
'fees': {
|
|
105
|
+
'trading': {
|
|
106
|
+
'tierBased': False,
|
|
107
|
+
'percentage': True,
|
|
108
|
+
'maker': self.parse_number('0.0025'),
|
|
109
|
+
'taker': self.parse_number('0.0025'),
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
async def fetch_markets(self, params={}) -> List[Market]:
|
|
115
|
+
"""
|
|
116
|
+
retrieves data on all markets for tehran_exchange
|
|
117
|
+
https://otc-api.tehran.exchange/otc/v1/market/pair
|
|
118
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
119
|
+
:returns dict[]: an array of objects representing market data
|
|
120
|
+
"""
|
|
121
|
+
response = await self.publicGetOtcV1MarketPair(params)
|
|
122
|
+
data = self.safe_dict(response, 'data', {})
|
|
123
|
+
pairs = self.safe_list(data, 'pairs', [])
|
|
124
|
+
result = []
|
|
125
|
+
for i in range(0, len(pairs)):
|
|
126
|
+
market = self.parse_market(pairs[i])
|
|
127
|
+
result.append(market)
|
|
128
|
+
return result
|
|
129
|
+
|
|
130
|
+
def parse_market(self, market) -> Market:
|
|
131
|
+
# {
|
|
132
|
+
# "id": 6054,
|
|
133
|
+
# "pair": "HBAR_USDT",
|
|
134
|
+
# "status": "TRADABLE",
|
|
135
|
+
# "tradable": True,
|
|
136
|
+
# "fiatOrder": False,
|
|
137
|
+
# "quoteName": "Tether",
|
|
138
|
+
# "baseName": "Hedera",
|
|
139
|
+
# "quoteNameFa": "تتر",
|
|
140
|
+
# "baseNameFa": "هدرا هش گراف ",
|
|
141
|
+
# "quoteImageUrl": "https://s3-dev.tehranex.com/asset/coin_icon/64/usdt.png",
|
|
142
|
+
# "baseImageUrl": "https://s3-dev.tehranex.com/asset/coin_icon/64/hbar.png",
|
|
143
|
+
# "quoteSymbol": "USDT",
|
|
144
|
+
# "baseSymbol": "HBAR",
|
|
145
|
+
# "amountPrecision": 2,
|
|
146
|
+
# "feePercentage": 0.25,
|
|
147
|
+
# "providerFeePercentage": 0.05,
|
|
148
|
+
# "maxQuoteAmount": 600000,
|
|
149
|
+
# "minBaseAmount": 0.01,
|
|
150
|
+
# "minQuoteAmount": 1,
|
|
151
|
+
# "pricePrecision": 5,
|
|
152
|
+
# "baseVirtualCurrencyId": 989,
|
|
153
|
+
# "quoteVirtualCurrencyId": 1
|
|
154
|
+
# }
|
|
155
|
+
id = self.safe_string(market, 'pair')
|
|
156
|
+
baseId = self.safe_string(market, 'baseSymbol')
|
|
157
|
+
quoteId = self.safe_string(market, 'quoteSymbol')
|
|
158
|
+
base = self.safe_currency_code(baseId)
|
|
159
|
+
quote = self.safe_currency_code(quoteId)
|
|
160
|
+
status = self.safe_string(market, 'status')
|
|
161
|
+
tradable = self.safe_bool(market, 'tradable', False)
|
|
162
|
+
active = (status == 'TRADABLE') and tradable
|
|
163
|
+
amountPrecision = self.safe_integer(market, 'amountPrecision')
|
|
164
|
+
pricePrecision = self.safe_integer(market, 'pricePrecision')
|
|
165
|
+
minBaseAmount = self.safe_string(market, 'minBaseAmount')
|
|
166
|
+
minQuoteAmount = self.safe_string(market, 'minQuoteAmount')
|
|
167
|
+
maxQuoteAmount = self.safe_string(market, 'maxQuoteAmount')
|
|
168
|
+
return {
|
|
169
|
+
'id': id,
|
|
170
|
+
'symbol': base + '/' + quote,
|
|
171
|
+
'base': base,
|
|
172
|
+
'quote': quote,
|
|
173
|
+
'settle': None,
|
|
174
|
+
'baseId': baseId,
|
|
175
|
+
'quoteId': quoteId,
|
|
176
|
+
'settleId': None,
|
|
177
|
+
'type': 'spot',
|
|
178
|
+
'spot': True,
|
|
179
|
+
'margin': False,
|
|
180
|
+
'swap': False,
|
|
181
|
+
'future': False,
|
|
182
|
+
'option': False,
|
|
183
|
+
'active': active,
|
|
184
|
+
'contract': False,
|
|
185
|
+
'linear': None,
|
|
186
|
+
'inverse': None,
|
|
187
|
+
'contractSize': None,
|
|
188
|
+
'expiry': None,
|
|
189
|
+
'expiryDatetime': None,
|
|
190
|
+
'strike': None,
|
|
191
|
+
'optionType': None,
|
|
192
|
+
'precision': {
|
|
193
|
+
'amount': amountPrecision,
|
|
194
|
+
'price': pricePrecision,
|
|
195
|
+
},
|
|
196
|
+
'limits': {
|
|
197
|
+
'leverage': {
|
|
198
|
+
'min': None,
|
|
199
|
+
'max': None,
|
|
200
|
+
},
|
|
201
|
+
'amount': {
|
|
202
|
+
'min': self.parse_number(minBaseAmount),
|
|
203
|
+
'max': None,
|
|
204
|
+
},
|
|
205
|
+
'price': {
|
|
206
|
+
'min': None,
|
|
207
|
+
'max': None,
|
|
208
|
+
},
|
|
209
|
+
'cost': {
|
|
210
|
+
'min': self.parse_number(minQuoteAmount),
|
|
211
|
+
'max': self.parse_number(maxQuoteAmount),
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
'created': None,
|
|
215
|
+
'info': market,
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
async def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
|
|
219
|
+
"""
|
|
220
|
+
fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
|
|
221
|
+
https://otc-api.tehran.exchange/otc/v1/market/pair
|
|
222
|
+
https://otc-api.tehran.exchange/otc/v1/market/order/pair/price
|
|
223
|
+
:param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
|
|
224
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
225
|
+
:returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
226
|
+
"""
|
|
227
|
+
await self.load_markets()
|
|
228
|
+
if symbols is not None:
|
|
229
|
+
symbols = self.market_symbols(symbols)
|
|
230
|
+
response = await self.publicGetOtcV1MarketPair(params)
|
|
231
|
+
data = self.safe_dict(response, 'data', {})
|
|
232
|
+
pairs = self.safe_list(data, 'pairs', [])
|
|
233
|
+
# filter symbols from pairs
|
|
234
|
+
filteredPairs = []
|
|
235
|
+
for i in range(0, len(pairs)):
|
|
236
|
+
pair = pairs[i]
|
|
237
|
+
pairId = self.safe_string(pair, 'pair')
|
|
238
|
+
symbol = self.safe_symbol(pairId)
|
|
239
|
+
if symbols.includes(symbol):
|
|
240
|
+
filteredPairs.append(pair)
|
|
241
|
+
result = {}
|
|
242
|
+
for i in range(0, len(filteredPairs)):
|
|
243
|
+
pairData = filteredPairs[i]
|
|
244
|
+
pairId = self.safe_string(pairData, 'pair')
|
|
245
|
+
# Fetch BUY price
|
|
246
|
+
request = {
|
|
247
|
+
'pair': pairId,
|
|
248
|
+
'side': 'BUY',
|
|
249
|
+
'basedOn': 'BASE',
|
|
250
|
+
'amount': 1,
|
|
251
|
+
}
|
|
252
|
+
priceResponse = await self.publicGetOtcV1MarketOrderPairPrice(request)
|
|
253
|
+
priceData = self.safe_dict(priceResponse, 'data', {})
|
|
254
|
+
price = self.safe_float(priceData, 'price', 0)
|
|
255
|
+
pairData['price'] = price
|
|
256
|
+
ticker = self.parse_ticker(pairData)
|
|
257
|
+
symbol = ticker['symbol']
|
|
258
|
+
result[symbol] = ticker
|
|
259
|
+
return self.filter_by_array_tickers(result, 'symbol', symbols)
|
|
260
|
+
|
|
261
|
+
async def fetch_ticker(self, symbol: str, params={}) -> Ticker:
|
|
262
|
+
"""
|
|
263
|
+
fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
|
264
|
+
https://otc-api.tehran.exchange/otc/v1/market/pair
|
|
265
|
+
:param str symbol: unified symbol of the market to fetch the ticker for
|
|
266
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
267
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
268
|
+
"""
|
|
269
|
+
ticker = await self.fetch_tickers([symbol])
|
|
270
|
+
return ticker[self.safe_symbol(symbol)]
|
|
271
|
+
|
|
272
|
+
def parse_ticker(self, ticker, market: Market = None) -> Ticker:
|
|
273
|
+
# {
|
|
274
|
+
# "id": 6054,
|
|
275
|
+
# "pair": "HBAR_USDT",
|
|
276
|
+
# "status": "TRADABLE",
|
|
277
|
+
# "tradable": True,
|
|
278
|
+
# "baseSymbol": "HBAR",
|
|
279
|
+
# "quoteSymbol": "USDT",
|
|
280
|
+
# ...
|
|
281
|
+
# "price": 12345,
|
|
282
|
+
# }
|
|
283
|
+
marketType = 'spot'
|
|
284
|
+
baseSymbol = self.safe_string(ticker, 'baseSymbol')
|
|
285
|
+
quoteSymbol = self.safe_string(ticker, 'quoteSymbol')
|
|
286
|
+
marketId = baseSymbol + '/' + quoteSymbol
|
|
287
|
+
symbol = self.safe_symbol(marketId, market, None, marketType)
|
|
288
|
+
price = self.safe_float(ticker, 'price')
|
|
289
|
+
return self.safe_ticker({
|
|
290
|
+
'symbol': symbol,
|
|
291
|
+
'timestamp': None,
|
|
292
|
+
'datetime': None,
|
|
293
|
+
'high': None,
|
|
294
|
+
'low': None,
|
|
295
|
+
'bid': price,
|
|
296
|
+
'bidVolume': None,
|
|
297
|
+
'ask': price,
|
|
298
|
+
'askVolume': None,
|
|
299
|
+
'open': None,
|
|
300
|
+
'close': price,
|
|
301
|
+
'last': price,
|
|
302
|
+
'previousClose': None,
|
|
303
|
+
'change': None,
|
|
304
|
+
'percentage': None,
|
|
305
|
+
'average': None,
|
|
306
|
+
'baseVolume': None,
|
|
307
|
+
'quoteVolume': None,
|
|
308
|
+
'info': ticker,
|
|
309
|
+
}, market)
|
|
310
|
+
|
|
311
|
+
def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
|
|
312
|
+
query = self.omit(params, self.extract_params(path))
|
|
313
|
+
url = self.urls['api']['public'] + '/' + path
|
|
314
|
+
if query:
|
|
315
|
+
url += '?' + self.urlencode(query)
|
|
316
|
+
headers = {'Content-Type': 'application/json'}
|
|
317
|
+
return {'url': url, 'method': method, 'body': body, 'headers': headers}
|
ccxt/async_support/toobit.py
CHANGED
|
@@ -113,6 +113,7 @@ class toobit(Exchange, ImplicitAPI):
|
|
|
113
113
|
'get': {
|
|
114
114
|
'quote/v1/ticker/24hr': 1,
|
|
115
115
|
'quote/v1/klines': 1,
|
|
116
|
+
'/api/v1/exchangeInfo': 1,
|
|
116
117
|
},
|
|
117
118
|
},
|
|
118
119
|
},
|
|
@@ -129,48 +130,98 @@ class toobit(Exchange, ImplicitAPI):
|
|
|
129
130
|
async def fetch_markets(self, params={}) -> List[Market]:
|
|
130
131
|
"""
|
|
131
132
|
retrieves data on all markets for toobit
|
|
132
|
-
https://
|
|
133
|
+
https://api.toobit.com/api/v1/exchangeInfo
|
|
133
134
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
134
135
|
:returns dict[]: an array of objects representing market data
|
|
135
136
|
"""
|
|
136
|
-
response = await self.
|
|
137
|
+
response = await self.publicGetApiV1ExchangeInfo()
|
|
138
|
+
symbols = self.safe_value(response, 'symbols', [])
|
|
137
139
|
result = []
|
|
138
|
-
for i in range(0, len(
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
140
|
+
for i in range(0, len(symbols)):
|
|
141
|
+
symbolData = symbols[i]
|
|
142
|
+
status = self.safe_value(symbolData, 'status')
|
|
143
|
+
symbol = self.safe_value(symbolData, 'symbol')
|
|
144
|
+
if status != 'TRADING' or symbol == 'TESTA1S3TESTX8Z9':
|
|
142
145
|
continue
|
|
143
|
-
market = self.parse_market(
|
|
146
|
+
market = self.parse_market(symbolData)
|
|
144
147
|
result.append(market)
|
|
145
148
|
return result
|
|
146
149
|
|
|
147
150
|
def parse_market(self, market) -> Market:
|
|
148
151
|
# {
|
|
149
|
-
#
|
|
150
|
-
#
|
|
151
|
-
#
|
|
152
|
-
#
|
|
153
|
-
#
|
|
154
|
-
#
|
|
155
|
-
#
|
|
156
|
-
#
|
|
157
|
-
#
|
|
158
|
-
#
|
|
159
|
-
#
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
152
|
+
# "filters": [
|
|
153
|
+
# {
|
|
154
|
+
# "minPrice": "0.01",
|
|
155
|
+
# "maxPrice": "10000000.00000000",
|
|
156
|
+
# "tickSize": "0.01",
|
|
157
|
+
# "filterType": "PRICE_FILTER"
|
|
158
|
+
# },
|
|
159
|
+
# {
|
|
160
|
+
# "minQty": "0.0001",
|
|
161
|
+
# "maxQty": "4000",
|
|
162
|
+
# "stepSize": "0.0001",
|
|
163
|
+
# "filterType": "LOT_SIZE"
|
|
164
|
+
# },
|
|
165
|
+
# {
|
|
166
|
+
# "minNotional": "5",
|
|
167
|
+
# "filterType": "MIN_NOTIONAL"
|
|
168
|
+
# }
|
|
169
|
+
# ],
|
|
170
|
+
# "exchangeId": "301",
|
|
171
|
+
# "symbol": "ETHUSDT",
|
|
172
|
+
# "symbolName": "ETHUSDT",
|
|
173
|
+
# "status": "TRADING",
|
|
174
|
+
# "baseAsset": "ETH",
|
|
175
|
+
# "baseAssetName": "ETH",
|
|
176
|
+
# "baseAssetPrecision": "0.0001",
|
|
177
|
+
# "quoteAsset": "USDT",
|
|
178
|
+
# "quoteAssetName": "USDT",
|
|
179
|
+
# "quotePrecision": "0.01",
|
|
180
|
+
# "icebergAllowed": False,
|
|
181
|
+
# "isAggregate": False,
|
|
182
|
+
# "allowMargin": True
|
|
183
|
+
# }
|
|
184
|
+
symbol = self.safe_value(market, 'symbol')
|
|
185
|
+
baseAsset = self.safe_value(market, 'baseAsset')
|
|
186
|
+
quoteAsset = self.safe_value(market, 'quoteAsset')
|
|
187
|
+
baseAssetPrecision = self.safe_value(market, 'baseAssetPrecision')
|
|
188
|
+
quotePrecision = self.safe_value(market, 'quotePrecision')
|
|
189
|
+
allowMargin = self.safe_value(market, 'allowMargin', False)
|
|
190
|
+
filters = self.safe_value(market, 'filters', [])
|
|
191
|
+
# Parse filters to extract limits and precision
|
|
192
|
+
minPrice = None
|
|
193
|
+
maxPrice = None
|
|
194
|
+
tickSize = None
|
|
195
|
+
minQty = None
|
|
196
|
+
maxQty = None
|
|
197
|
+
stepSize = None
|
|
198
|
+
minNotional = None
|
|
199
|
+
minAmount = None
|
|
200
|
+
maxAmount = None
|
|
201
|
+
for i in range(0, len(filters)):
|
|
202
|
+
filter = filters[i]
|
|
203
|
+
filterType = self.safe_value(filter, 'filterType')
|
|
204
|
+
if filterType == 'PRICE_FILTER':
|
|
205
|
+
minPrice = self.safe_number(filter, 'minPrice')
|
|
206
|
+
maxPrice = self.safe_number(filter, 'maxPrice')
|
|
207
|
+
tickSize = self.safe_number(filter, 'tickSize')
|
|
208
|
+
elif filterType == 'LOT_SIZE':
|
|
209
|
+
minQty = self.safe_number(filter, 'minQty')
|
|
210
|
+
maxQty = self.safe_number(filter, 'maxQty')
|
|
211
|
+
stepSize = self.safe_number(filter, 'stepSize')
|
|
212
|
+
elif filterType == 'MIN_NOTIONAL':
|
|
213
|
+
minNotional = self.safe_number(filter, 'minNotional')
|
|
214
|
+
elif filterType == 'TRADE_AMOUNT':
|
|
215
|
+
minAmount = self.safe_number(filter, 'minAmount')
|
|
216
|
+
maxAmount = self.safe_number(filter, 'maxAmount')
|
|
169
217
|
id = symbol
|
|
170
|
-
base = self.safe_currency_code(
|
|
171
|
-
quote = self.safe_currency_code(
|
|
172
|
-
baseId =
|
|
173
|
-
quoteId =
|
|
218
|
+
base = self.safe_currency_code(baseAsset)
|
|
219
|
+
quote = self.safe_currency_code(quoteAsset)
|
|
220
|
+
baseId = baseAsset.lower()
|
|
221
|
+
quoteId = quoteAsset.lower()
|
|
222
|
+
# Calculate precision from step sizes and precision strings
|
|
223
|
+
amountPrecision = str(self.precision_from_string(stepSize)) if stepSize else self.precision_from_string(baseAssetPrecision)
|
|
224
|
+
pricePrecision = str(self.precision_from_string(tickSize)) if tickSize else self.precision_from_string(quotePrecision)
|
|
174
225
|
return {
|
|
175
226
|
'id': id,
|
|
176
227
|
'symbol': base + '/' + quote,
|
|
@@ -182,7 +233,7 @@ class toobit(Exchange, ImplicitAPI):
|
|
|
182
233
|
'settleId': None,
|
|
183
234
|
'type': 'spot',
|
|
184
235
|
'spot': True,
|
|
185
|
-
'margin':
|
|
236
|
+
'margin': allowMargin,
|
|
186
237
|
'swap': False,
|
|
187
238
|
'future': False,
|
|
188
239
|
'option': False,
|
|
@@ -196,8 +247,8 @@ class toobit(Exchange, ImplicitAPI):
|
|
|
196
247
|
'strike': None,
|
|
197
248
|
'optionType': None,
|
|
198
249
|
'precision': {
|
|
199
|
-
'amount':
|
|
200
|
-
'price':
|
|
250
|
+
'amount': amountPrecision,
|
|
251
|
+
'price': pricePrecision,
|
|
201
252
|
},
|
|
202
253
|
'limits': {
|
|
203
254
|
'leverage': {
|
|
@@ -205,16 +256,16 @@ class toobit(Exchange, ImplicitAPI):
|
|
|
205
256
|
'max': None,
|
|
206
257
|
},
|
|
207
258
|
'amount': {
|
|
208
|
-
'min':
|
|
209
|
-
'max':
|
|
259
|
+
'min': minQty,
|
|
260
|
+
'max': maxQty,
|
|
210
261
|
},
|
|
211
262
|
'price': {
|
|
212
|
-
'min':
|
|
213
|
-
'max':
|
|
263
|
+
'min': minPrice,
|
|
264
|
+
'max': maxPrice,
|
|
214
265
|
},
|
|
215
266
|
'cost': {
|
|
216
|
-
'min':
|
|
217
|
-
'max':
|
|
267
|
+
'min': minNotional or minAmount,
|
|
268
|
+
'max': maxAmount,
|
|
218
269
|
},
|
|
219
270
|
},
|
|
220
271
|
'created': None,
|
|
@@ -224,7 +275,7 @@ class toobit(Exchange, ImplicitAPI):
|
|
|
224
275
|
async def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
|
|
225
276
|
"""
|
|
226
277
|
fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
|
|
227
|
-
https://
|
|
278
|
+
https://toobit-docs.github.io/apidocs/spot/v1/en/#tickers
|
|
228
279
|
:param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
|
|
229
280
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
230
281
|
:returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
@@ -246,7 +297,7 @@ class toobit(Exchange, ImplicitAPI):
|
|
|
246
297
|
async def fetch_ticker(self, symbol: str, params={}) -> Ticker:
|
|
247
298
|
"""
|
|
248
299
|
fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
|
249
|
-
https://
|
|
300
|
+
https://toobit-docs.github.io/apidocs/spot/v1/en/#ticker
|
|
250
301
|
:param str symbol: unified symbol of the market to fetch the ticker for
|
|
251
302
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
252
303
|
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
@@ -315,7 +366,7 @@ class toobit(Exchange, ImplicitAPI):
|
|
|
315
366
|
async def fetch_ohlcv(self, symbol: str, timeframe='1h', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
|
316
367
|
"""
|
|
317
368
|
fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
318
|
-
https://
|
|
369
|
+
https://toobit-docs.github.io/apidocs/spot/v1/en/#chart
|
|
319
370
|
:param str symbol: unified symbol of the market to fetch OHLCV data for
|
|
320
371
|
:param str timeframe: the length of time each candle represents
|
|
321
372
|
:param int [since]: timestamp in ms of the earliest candle to fetch
|