ccxt-look 1.81.50

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.
Files changed (264) hide show
  1. package/.cache/eslintcache +1 -0
  2. package/.dockerignore +6 -0
  3. package/.eslintignore +1 -0
  4. package/.gitattributes +5 -0
  5. package/.readthedocs.yaml +16 -0
  6. package/CONTRIBUTING.md +1049 -0
  7. package/LICENSE.txt +21 -0
  8. package/README.md +537 -0
  9. package/SECURITY.md +5 -0
  10. package/build/cleanup-old-tags.js +94 -0
  11. package/build/countries.js +256 -0
  12. package/build/export-exchanges.js +520 -0
  13. package/build/fs.js +51 -0
  14. package/build/transpile.js +1772 -0
  15. package/build/vss.js +78 -0
  16. package/ccxt.browser.js +7 -0
  17. package/ccxt.d.ts +692 -0
  18. package/ccxt.js +171 -0
  19. package/cleanup.sh +2 -0
  20. package/composer-install.sh +20 -0
  21. package/dist/ccxt.browser.js +208383 -0
  22. package/gource.sh +3 -0
  23. package/index.html +7 -0
  24. package/js/.eslintrc +87 -0
  25. package/js/aax.js +2686 -0
  26. package/js/ascendex.js +2584 -0
  27. package/js/base/.eslintrc.js +43 -0
  28. package/js/base/Exchange.js +2371 -0
  29. package/js/base/Precise.js +283 -0
  30. package/js/base/errorHierarchy.js +47 -0
  31. package/js/base/errors.js +55 -0
  32. package/js/base/functions/crypto.js +158 -0
  33. package/js/base/functions/encode.js +118 -0
  34. package/js/base/functions/generic.js +270 -0
  35. package/js/base/functions/misc.js +138 -0
  36. package/js/base/functions/number.js +329 -0
  37. package/js/base/functions/platform.js +38 -0
  38. package/js/base/functions/string.js +21 -0
  39. package/js/base/functions/throttle.js +79 -0
  40. package/js/base/functions/time.js +210 -0
  41. package/js/base/functions/type.js +66 -0
  42. package/js/base/functions.js +28 -0
  43. package/js/bequant.js +32 -0
  44. package/js/bibox.js +1407 -0
  45. package/js/bigone.js +1366 -0
  46. package/js/binance.js +5652 -0
  47. package/js/binancecoinm.js +46 -0
  48. package/js/binanceus.js +46 -0
  49. package/js/binanceusdm.js +49 -0
  50. package/js/bit2c.js +535 -0
  51. package/js/bitbank.js +842 -0
  52. package/js/bitbay.js +16 -0
  53. package/js/bitbns.js +1073 -0
  54. package/js/bitcoincom.js +15 -0
  55. package/js/bitfinex.js +1433 -0
  56. package/js/bitfinex2.js +2025 -0
  57. package/js/bitflyer.js +840 -0
  58. package/js/bitforex.js +614 -0
  59. package/js/bitget.js +2397 -0
  60. package/js/bithumb.js +980 -0
  61. package/js/bitmart.js +2516 -0
  62. package/js/bitmex.js +1809 -0
  63. package/js/bitopro.js +1443 -0
  64. package/js/bitpanda.js +1782 -0
  65. package/js/bitrue.js +1747 -0
  66. package/js/bitso.js +1062 -0
  67. package/js/bitstamp.js +1757 -0
  68. package/js/bitstamp1.js +343 -0
  69. package/js/bittrex.js +1876 -0
  70. package/js/bitvavo.js +1579 -0
  71. package/js/bkex.js +1233 -0
  72. package/js/bl3p.js +346 -0
  73. package/js/blockchaincom.js +969 -0
  74. package/js/btcalpha.js +680 -0
  75. package/js/btcbox.js +477 -0
  76. package/js/btcmarkets.js +1022 -0
  77. package/js/btctradeua.js +466 -0
  78. package/js/btcturk.js +734 -0
  79. package/js/buda.js +946 -0
  80. package/js/bw.js +1265 -0
  81. package/js/bybit.js +3372 -0
  82. package/js/bytetrade.js +1336 -0
  83. package/js/cdax.js +1646 -0
  84. package/js/cex.js +1410 -0
  85. package/js/coinbase.js +1342 -0
  86. package/js/coinbaseprime.js +31 -0
  87. package/js/coinbasepro.js +1466 -0
  88. package/js/coincheck.js +755 -0
  89. package/js/coinex.js +3400 -0
  90. package/js/coinfalcon.js +880 -0
  91. package/js/coinmate.js +794 -0
  92. package/js/coinone.js +816 -0
  93. package/js/coinspot.js +345 -0
  94. package/js/crex24.js +1636 -0
  95. package/js/cryptocom.js +1832 -0
  96. package/js/currencycom.js +1748 -0
  97. package/js/delta.js +1547 -0
  98. package/js/deribit.js +2148 -0
  99. package/js/digifinex.js +1585 -0
  100. package/js/eqonex.js +1660 -0
  101. package/js/exmo.js +1670 -0
  102. package/js/fairdesk.js +1231 -0
  103. package/js/flowbtc.js +35 -0
  104. package/js/fmfwio.js +34 -0
  105. package/js/ftx.js +2751 -0
  106. package/js/ftxus.js +38 -0
  107. package/js/gateio.js +4174 -0
  108. package/js/gemini.js +1397 -0
  109. package/js/hitbtc.js +1343 -0
  110. package/js/hitbtc3.js +2329 -0
  111. package/js/hollaex.js +1486 -0
  112. package/js/huobi.js +5706 -0
  113. package/js/huobijp.js +1710 -0
  114. package/js/huobipro.js +18 -0
  115. package/js/idex.js +1439 -0
  116. package/js/independentreserve.js +649 -0
  117. package/js/indodax.js +742 -0
  118. package/js/itbit.js +722 -0
  119. package/js/kraken.js +2179 -0
  120. package/js/kucoin.js +2571 -0
  121. package/js/kucoinfutures.js +1771 -0
  122. package/js/kuna.js +809 -0
  123. package/js/latoken.js +1445 -0
  124. package/js/lbank.js +760 -0
  125. package/js/liquid.js +1432 -0
  126. package/js/luno.js +873 -0
  127. package/js/lykke.js +1147 -0
  128. package/js/mercado.js +771 -0
  129. package/js/mexc.js +3151 -0
  130. package/js/ndax.js +2233 -0
  131. package/js/novadax.js +1318 -0
  132. package/js/oceanex.js +816 -0
  133. package/js/okcoin.js +3841 -0
  134. package/js/okex.js +16 -0
  135. package/js/okex5.js +16 -0
  136. package/js/okx.js +4795 -0
  137. package/js/paymium.js +498 -0
  138. package/js/phemex.js +2957 -0
  139. package/js/poloniex.js +1674 -0
  140. package/js/probit.js +1346 -0
  141. package/js/qtrade.js +1588 -0
  142. package/js/ripio.js +1061 -0
  143. package/js/static_dependencies/BN/bn.js +3526 -0
  144. package/js/static_dependencies/README.md +1 -0
  145. package/js/static_dependencies/crypto-js/crypto-js.js +5988 -0
  146. package/js/static_dependencies/elliptic/lib/elliptic/curve/base.js +375 -0
  147. package/js/static_dependencies/elliptic/lib/elliptic/curve/edwards.js +433 -0
  148. package/js/static_dependencies/elliptic/lib/elliptic/curve/index.js +8 -0
  149. package/js/static_dependencies/elliptic/lib/elliptic/curve/mont.js +180 -0
  150. package/js/static_dependencies/elliptic/lib/elliptic/curve/short.js +938 -0
  151. package/js/static_dependencies/elliptic/lib/elliptic/curves.js +204 -0
  152. package/js/static_dependencies/elliptic/lib/elliptic/ec/index.js +240 -0
  153. package/js/static_dependencies/elliptic/lib/elliptic/ec/key.js +119 -0
  154. package/js/static_dependencies/elliptic/lib/elliptic/ec/signature.js +24 -0
  155. package/js/static_dependencies/elliptic/lib/elliptic/eddsa/index.js +145 -0
  156. package/js/static_dependencies/elliptic/lib/elliptic/eddsa/key.js +100 -0
  157. package/js/static_dependencies/elliptic/lib/elliptic/eddsa/signature.js +65 -0
  158. package/js/static_dependencies/elliptic/lib/elliptic/precomputed/secp256k1.js +780 -0
  159. package/js/static_dependencies/elliptic/lib/elliptic/utils.js +214 -0
  160. package/js/static_dependencies/elliptic/lib/elliptic.js +22 -0
  161. package/js/static_dependencies/elliptic/lib/hmac-drbg/hmac-drbg.js +114 -0
  162. package/js/static_dependencies/fetch-ponyfill/fetch-node.js +39 -0
  163. package/js/static_dependencies/node-fetch/index.js +1564 -0
  164. package/js/static_dependencies/node-rsa/NodeRSA.js +223 -0
  165. package/js/static_dependencies/node-rsa/asn1/ber/errors.js +13 -0
  166. package/js/static_dependencies/node-rsa/asn1/ber/index.js +21 -0
  167. package/js/static_dependencies/node-rsa/asn1/ber/reader.js +262 -0
  168. package/js/static_dependencies/node-rsa/asn1/ber/types.js +36 -0
  169. package/js/static_dependencies/node-rsa/asn1/index.js +17 -0
  170. package/js/static_dependencies/node-rsa/encryptEngines/js.js +34 -0
  171. package/js/static_dependencies/node-rsa/formats/components.js +71 -0
  172. package/js/static_dependencies/node-rsa/formats/formats.js +31 -0
  173. package/js/static_dependencies/node-rsa/formats/pkcs1.js +148 -0
  174. package/js/static_dependencies/node-rsa/formats/pkcs8.js +187 -0
  175. package/js/static_dependencies/node-rsa/libs/jsbn.js +1252 -0
  176. package/js/static_dependencies/node-rsa/libs/rsa.js +147 -0
  177. package/js/static_dependencies/node-rsa/schemes/pkcs1.js +176 -0
  178. package/js/static_dependencies/node-rsa/schemes/schemes.js +21 -0
  179. package/js/static_dependencies/node-rsa/utils.js +98 -0
  180. package/js/static_dependencies/qs/formats.js +18 -0
  181. package/js/static_dependencies/qs/index.js +11 -0
  182. package/js/static_dependencies/qs/parse.js +242 -0
  183. package/js/static_dependencies/qs/stringify.js +269 -0
  184. package/js/static_dependencies/qs/utils.js +230 -0
  185. package/js/stex.js +1925 -0
  186. package/js/test/.eslintrc.js +42 -0
  187. package/js/test/Exchange/test.balance.js +61 -0
  188. package/js/test/Exchange/test.borrowRate.js +32 -0
  189. package/js/test/Exchange/test.currency.js +52 -0
  190. package/js/test/Exchange/test.fetchBalance.js +23 -0
  191. package/js/test/Exchange/test.fetchBorrowInterest.js +59 -0
  192. package/js/test/Exchange/test.fetchBorrowRate.js +32 -0
  193. package/js/test/Exchange/test.fetchBorrowRates.js +28 -0
  194. package/js/test/Exchange/test.fetchClosedOrders.js +32 -0
  195. package/js/test/Exchange/test.fetchCurrencies.js +35 -0
  196. package/js/test/Exchange/test.fetchDeposits.js +31 -0
  197. package/js/test/Exchange/test.fetchFundingFees.js +19 -0
  198. package/js/test/Exchange/test.fetchFundingRateHistory.js +40 -0
  199. package/js/test/Exchange/test.fetchL2OrderBook.js +23 -0
  200. package/js/test/Exchange/test.fetchLedger.js +42 -0
  201. package/js/test/Exchange/test.fetchLeverageTiers.js +33 -0
  202. package/js/test/Exchange/test.fetchMarketLeverageTiers.js +22 -0
  203. package/js/test/Exchange/test.fetchMarkets.js +33 -0
  204. package/js/test/Exchange/test.fetchMyTrades.js +42 -0
  205. package/js/test/Exchange/test.fetchOHLCV.js +46 -0
  206. package/js/test/Exchange/test.fetchOpenOrders.js +36 -0
  207. package/js/test/Exchange/test.fetchOrderBook.js +25 -0
  208. package/js/test/Exchange/test.fetchOrderBooks.js +35 -0
  209. package/js/test/Exchange/test.fetchOrders.js +41 -0
  210. package/js/test/Exchange/test.fetchPositions.js +47 -0
  211. package/js/test/Exchange/test.fetchStatus.js +35 -0
  212. package/js/test/Exchange/test.fetchTicker.js +38 -0
  213. package/js/test/Exchange/test.fetchTickers.js +49 -0
  214. package/js/test/Exchange/test.fetchTrades.js +39 -0
  215. package/js/test/Exchange/test.fetchTradingFee.js +18 -0
  216. package/js/test/Exchange/test.fetchTradingFees.js +22 -0
  217. package/js/test/Exchange/test.fetchTransactions.js +31 -0
  218. package/js/test/Exchange/test.fetchWithdrawals.js +31 -0
  219. package/js/test/Exchange/test.ledgerItem.js +46 -0
  220. package/js/test/Exchange/test.leverageTier.js +33 -0
  221. package/js/test/Exchange/test.loadMarkets.js +35 -0
  222. package/js/test/Exchange/test.market.js +129 -0
  223. package/js/test/Exchange/test.ohlcv.js +33 -0
  224. package/js/test/Exchange/test.order.js +62 -0
  225. package/js/test/Exchange/test.orderbook.js +61 -0
  226. package/js/test/Exchange/test.position.js +21 -0
  227. package/js/test/Exchange/test.throttle.js +94 -0
  228. package/js/test/Exchange/test.ticker.js +95 -0
  229. package/js/test/Exchange/test.trade.js +68 -0
  230. package/js/test/Exchange/test.tradingFee.js +34 -0
  231. package/js/test/Exchange/test.transaction.js +35 -0
  232. package/js/test/base/.eslintrc +38 -0
  233. package/js/test/base/functions/test.crypto.js +110 -0
  234. package/js/test/base/functions/test.datetime.js +62 -0
  235. package/js/test/base/functions/test.generic.js +152 -0
  236. package/js/test/base/functions/test.number.js +362 -0
  237. package/js/test/base/functions/test.time.js +56 -0
  238. package/js/test/base/functions/test.type.js +53 -0
  239. package/js/test/base/test.base.js +193 -0
  240. package/js/test/errors/test.InsufficientFunds.js +86 -0
  241. package/js/test/errors/test.InvalidNonce.js +64 -0
  242. package/js/test/errors/test.InvalidOrder.js +35 -0
  243. package/js/test/errors/test.OrderNotFound.js +39 -0
  244. package/js/test/test.js +426 -0
  245. package/js/test/test.timeout_hang.js +12 -0
  246. package/js/therock.js +1431 -0
  247. package/js/tidebit.js +632 -0
  248. package/js/tidex.js +939 -0
  249. package/js/timex.js +1283 -0
  250. package/js/upbit.js +1622 -0
  251. package/js/vcc.js +1353 -0
  252. package/js/wavesexchange.js +2185 -0
  253. package/js/wazirx.js +732 -0
  254. package/js/whitebit.js +1352 -0
  255. package/js/woo.js +1577 -0
  256. package/js/xena.js +1948 -0
  257. package/js/yobit.js +1129 -0
  258. package/js/zaif.js +647 -0
  259. package/js/zb.js +4088 -0
  260. package/js/zipmex.js +40 -0
  261. package/js/zonda.js +1497 -0
  262. package/multilang.sh +159 -0
  263. package/package.json +591 -0
  264. package/postinstall.js +103 -0
package/js/gemini.js ADDED
@@ -0,0 +1,1397 @@
1
+ 'use strict';
2
+
3
+ // ---------------------------------------------------------------------------
4
+
5
+ const Exchange = require ('./base/Exchange');
6
+ const { ExchangeError, ArgumentsRequired, BadRequest, OrderNotFound, InvalidOrder, InvalidNonce, InsufficientFunds, AuthenticationError, PermissionDenied, NotSupported, OnMaintenance, RateLimitExceeded, ExchangeNotAvailable } = require ('./base/errors');
7
+ const { TICK_SIZE } = require ('./base/functions/number');
8
+ const Precise = require ('./base/Precise');
9
+
10
+ // ---------------------------------------------------------------------------
11
+
12
+ module.exports = class gemini extends Exchange {
13
+ describe () {
14
+ return this.deepExtend (super.describe (), {
15
+ 'id': 'gemini',
16
+ 'name': 'Gemini',
17
+ 'countries': [ 'US' ],
18
+ // 600 requests a minute = 10 requests per second => 1000ms / 10 = 100ms between requests (private endpoints)
19
+ // 120 requests a minute = 2 requests per second => ( 1000ms / rateLimit ) / 2 = 5 (public endpoints)
20
+ 'rateLimit': 100,
21
+ 'version': 'v1',
22
+ 'has': {
23
+ 'CORS': undefined,
24
+ 'spot': true,
25
+ 'margin': false,
26
+ 'swap': false,
27
+ 'future': false,
28
+ 'option': false,
29
+ 'addMargin': false,
30
+ 'cancelOrder': true,
31
+ 'createDepositAddress': true,
32
+ 'createMarketOrder': undefined,
33
+ 'createOrder': true,
34
+ 'createReduceOnlyOrder': false,
35
+ 'fetchBalance': true,
36
+ 'fetchBidsAsks': undefined,
37
+ 'fetchBorrowRate': false,
38
+ 'fetchBorrowRateHistories': false,
39
+ 'fetchBorrowRateHistory': false,
40
+ 'fetchBorrowRates': false,
41
+ 'fetchBorrowRatesPerSymbol': false,
42
+ 'fetchClosedOrders': undefined,
43
+ 'fetchDepositAddress': undefined, // TODO
44
+ 'fetchDepositAddressesByNetwork': true,
45
+ 'fetchDeposits': undefined,
46
+ 'fetchFundingHistory': false,
47
+ 'fetchFundingRate': false,
48
+ 'fetchFundingRateHistory': false,
49
+ 'fetchFundingRates': false,
50
+ 'fetchIndexOHLCV': false,
51
+ 'fetchLeverage': false,
52
+ 'fetchLeverageTiers': false,
53
+ 'fetchMarkets': true,
54
+ 'fetchMarkOHLCV': false,
55
+ 'fetchMyTrades': true,
56
+ 'fetchOHLCV': true,
57
+ 'fetchOpenOrders': true,
58
+ 'fetchOrder': true,
59
+ 'fetchOrderBook': true,
60
+ 'fetchOrders': undefined,
61
+ 'fetchPosition': false,
62
+ 'fetchPositions': false,
63
+ 'fetchPositionsRisk': false,
64
+ 'fetchPremiumIndexOHLCV': false,
65
+ 'fetchTicker': true,
66
+ 'fetchTickers': true,
67
+ 'fetchTrades': true,
68
+ 'fetchTradingFee': false,
69
+ 'fetchTradingFees': true,
70
+ 'fetchTransactions': true,
71
+ 'fetchWithdrawals': undefined,
72
+ 'postOnly': true,
73
+ 'reduceMargin': false,
74
+ 'setLeverage': false,
75
+ 'setMarginMode': false,
76
+ 'setPositionMode': false,
77
+ 'withdraw': true,
78
+ },
79
+ 'urls': {
80
+ 'logo': 'https://user-images.githubusercontent.com/1294454/27816857-ce7be644-6096-11e7-82d6-3c257263229c.jpg',
81
+ 'api': {
82
+ 'public': 'https://api.gemini.com',
83
+ 'private': 'https://api.gemini.com',
84
+ 'web': 'https://docs.gemini.com',
85
+ },
86
+ 'www': 'https://gemini.com/',
87
+ 'doc': [
88
+ 'https://docs.gemini.com/rest-api',
89
+ 'https://docs.sandbox.gemini.com',
90
+ ],
91
+ 'test': {
92
+ 'public': 'https://api.sandbox.gemini.com',
93
+ 'private': 'https://api.sandbox.gemini.com',
94
+ // use the true doc instead of the sandbox doc
95
+ // since they differ in parsing
96
+ // https://github.com/ccxt/ccxt/issues/7874
97
+ // https://github.com/ccxt/ccxt/issues/7894
98
+ 'web': 'https://docs.gemini.com',
99
+ },
100
+ 'fees': [
101
+ 'https://gemini.com/api-fee-schedule',
102
+ 'https://gemini.com/trading-fees',
103
+ 'https://gemini.com/transfer-fees',
104
+ ],
105
+ },
106
+ 'api': {
107
+ 'web': {
108
+ 'get': [
109
+ 'rest-api',
110
+ ],
111
+ },
112
+ 'public': {
113
+ 'get': {
114
+ 'v1/symbols': 5,
115
+ 'v1/symbols/details/{symbol}': 5,
116
+ 'v1/pubticker/{symbol}': 5,
117
+ 'v2/ticker/{symbol}': 5,
118
+ 'v2/candles/{symbol}/{timeframe}': 5,
119
+ 'v1/trades/{symbol}': 5,
120
+ 'v1/auction/{symbol}': 5,
121
+ 'v1/auction/{symbol}/history': 5,
122
+ 'v1/pricefeed': 5,
123
+ 'v1/book/{symbol}': 5,
124
+ 'v1/earn/rates': 5,
125
+ },
126
+ },
127
+ 'private': {
128
+ 'post': {
129
+ 'v1/order/new': 1,
130
+ 'v1/order/cancel': 1,
131
+ 'v1/wrap/{symbol}': 1,
132
+ 'v1/order/cancel/session': 1,
133
+ 'v1/order/cancel/all': 1,
134
+ 'v1/order/status': 1,
135
+ 'v1/orders': 1,
136
+ 'v1/mytrades': 1,
137
+ 'v1/notionalvolume': 1,
138
+ 'v1/tradevolume': 1,
139
+ 'v1/clearing/new': 1,
140
+ 'v1/clearing/status': 1,
141
+ 'v1/clearing/cancel': 1,
142
+ 'v1/clearing/confirm': 1,
143
+ 'v1/balances': 1,
144
+ 'v1/notionalbalances/{currency}': 1,
145
+ 'v1/transfers': 1,
146
+ 'v1/addresses/{network}': 1,
147
+ 'v1/deposit/{network}/newAddress': 1,
148
+ 'v1/deposit/{currency}/newAddress': 1,
149
+ 'v1/withdraw/{currency}': 1,
150
+ 'v1/account/transfer/{currency}': 1,
151
+ 'v1/payments/addbank': 1,
152
+ 'v1/payments/methods': 1,
153
+ 'v1/payments/sen/withdraw': 1,
154
+ 'v1/balances/earn': 1,
155
+ 'v1/earn/interest': 1,
156
+ 'v1/approvedAddresses/{network}/request': 1,
157
+ 'v1/approvedAddresses/account/{network}': 1,
158
+ 'v1/approvedAddresses/{network}/remove': 1,
159
+ 'v1/account': 1,
160
+ 'v1/account/create': 1,
161
+ 'v1/account/list': 1,
162
+ 'v1/heartbeat': 1,
163
+ },
164
+ },
165
+ },
166
+ 'precisionMode': TICK_SIZE,
167
+ 'fees': {
168
+ 'trading': {
169
+ 'taker': 0.004,
170
+ 'maker': 0.002,
171
+ },
172
+ },
173
+ 'httpExceptions': {
174
+ '400': BadRequest, // Auction not open or paused, ineligible timing, market not open, or the request was malformed, in the case of a private API request, missing or malformed Gemini private API authentication headers
175
+ '403': PermissionDenied, // The API key is missing the role necessary to access this private API endpoint
176
+ '404': OrderNotFound, // Unknown API entry point or Order not found
177
+ '406': InsufficientFunds, // Insufficient Funds
178
+ '429': RateLimitExceeded, // Rate Limiting was applied
179
+ '500': ExchangeError, // The server encountered an error
180
+ '502': ExchangeNotAvailable, // Technical issues are preventing the request from being satisfied
181
+ '503': OnMaintenance, // The exchange is down for maintenance
182
+ },
183
+ 'timeframes': {
184
+ '1m': '1m',
185
+ '5m': '5m',
186
+ '15m': '15m',
187
+ '30m': '30m',
188
+ '1h': '1hr',
189
+ '6h': '6hr',
190
+ '1d': '1day',
191
+ },
192
+ 'exceptions': {
193
+ 'exact': {
194
+ 'AuctionNotOpen': BadRequest, // Failed to place an auction-only order because there is no current auction open for this symbol
195
+ 'ClientOrderIdTooLong': BadRequest, // The Client Order ID must be under 100 characters
196
+ 'ClientOrderIdMustBeString': BadRequest, // The Client Order ID must be a string
197
+ 'ConflictingOptions': BadRequest, // New orders using a combination of order execution options are not supported
198
+ 'EndpointMismatch': BadRequest, // The request was submitted to an endpoint different than the one in the payload
199
+ 'EndpointNotFound': BadRequest, // No endpoint was specified
200
+ 'IneligibleTiming': BadRequest, // Failed to place an auction order for the current auction on this symbol because the timing is not eligible, new orders may only be placed before the auction begins.
201
+ 'InsufficientFunds': InsufficientFunds, // The order was rejected because of insufficient funds
202
+ 'InvalidJson': BadRequest, // The JSON provided is invalid
203
+ 'InvalidNonce': InvalidNonce, // The nonce was not greater than the previously used nonce, or was not present
204
+ 'InvalidOrderType': InvalidOrder, // An unknown order type was provided
205
+ 'InvalidPrice': InvalidOrder, // For new orders, the price was invalid
206
+ 'InvalidQuantity': InvalidOrder, // A negative or otherwise invalid quantity was specified
207
+ 'InvalidSide': InvalidOrder, // For new orders, and invalid side was specified
208
+ 'InvalidSignature': AuthenticationError, // The signature did not match the expected signature
209
+ 'InvalidSymbol': BadRequest, // An invalid symbol was specified
210
+ 'InvalidTimestampInPayload': BadRequest, // The JSON payload contained a timestamp parameter with an unsupported value.
211
+ 'Maintenance': OnMaintenance, // The system is down for maintenance
212
+ 'MarketNotOpen': InvalidOrder, // The order was rejected because the market is not accepting new orders
213
+ 'MissingApikeyHeader': AuthenticationError, // The X-GEMINI-APIKEY header was missing
214
+ 'MissingOrderField': InvalidOrder, // A required order_id field was not specified
215
+ 'MissingRole': AuthenticationError, // The API key used to access this endpoint does not have the required role assigned to it
216
+ 'MissingPayloadHeader': AuthenticationError, // The X-GEMINI-PAYLOAD header was missing
217
+ 'MissingSignatureHeader': AuthenticationError, // The X-GEMINI-SIGNATURE header was missing
218
+ 'NoSSL': AuthenticationError, // You must use HTTPS to access the API
219
+ 'OptionsMustBeArray': BadRequest, // The options parameter must be an array.
220
+ 'OrderNotFound': OrderNotFound, // The order specified was not found
221
+ 'RateLimit': RateLimitExceeded, // Requests were made too frequently. See Rate Limits below.
222
+ 'System': ExchangeError, // We are experiencing technical issues
223
+ 'UnsupportedOption': BadRequest, // This order execution option is not supported.
224
+ },
225
+ 'broad': {
226
+ 'The Gemini Exchange is currently undergoing maintenance.': OnMaintenance, // The Gemini Exchange is currently undergoing maintenance. Please check https://status.gemini.com/ for more information.
227
+ 'We are investigating technical issues with the Gemini Exchange.': ExchangeNotAvailable, // We are investigating technical issues with the Gemini Exchange. Please check https://status.gemini.com/ for more information.
228
+ },
229
+ },
230
+ 'options': {
231
+ 'fetchMarketsMethod': 'fetch_markets_from_web',
232
+ 'fetchTickerMethod': 'fetchTickerV1', // fetchTickerV1, fetchTickerV2, fetchTickerV1AndV2
233
+ 'networkIds': {
234
+ 'bitcoin': 'BTC',
235
+ 'ethereum': 'ERC20',
236
+ 'bitcoincash': 'BCH',
237
+ 'litecoin': 'LTC',
238
+ 'zcash': 'ZEC',
239
+ 'filecoin': 'FIL',
240
+ 'dogecoin': 'DOGE',
241
+ 'tezos': 'XTZ',
242
+ },
243
+ 'networks': {
244
+ 'BTC': 'bitcoin',
245
+ 'ERC20': 'ethereum',
246
+ 'BCH': 'bitcoincash',
247
+ 'LTC': 'litecoin',
248
+ 'ZEC': 'zcash',
249
+ 'FIL': 'filecoin',
250
+ 'DOGE': 'dogecoin',
251
+ 'XTZ': 'tezos',
252
+ },
253
+ },
254
+ });
255
+ }
256
+
257
+ async fetchMarkets (params = {}) {
258
+ const method = this.safeValue (this.options, 'fetchMarketsMethod', 'fetch_markets_from_api');
259
+ return await this[method] (params);
260
+ }
261
+
262
+ async fetchMarketsFromWeb (params = {}) {
263
+ const response = await this.webGetRestApi (params);
264
+ const sections = response.split ('<h1 id="symbols-and-minimums">Symbols and minimums</h1>');
265
+ const numSections = sections.length;
266
+ const error = this.id + ' fetchMarketsFromWeb() the ' + this.name + ' API doc HTML markup has changed, breaking the parser of order limits and precision info for ' + this.name + ' markets.';
267
+ if (numSections !== 2) {
268
+ throw new NotSupported (error);
269
+ }
270
+ const tables = sections[1].split ('tbody>');
271
+ const numTables = tables.length;
272
+ if (numTables < 2) {
273
+ throw new NotSupported (error);
274
+ }
275
+ const rows = tables[1].split ("\n<tr>\n"); // eslint-disable-line quotes
276
+ const numRows = rows.length;
277
+ if (numRows < 2) {
278
+ throw new NotSupported (error);
279
+ }
280
+ const result = [];
281
+ // skip the first element (empty string)
282
+ for (let i = 1; i < numRows; i++) {
283
+ const row = rows[i];
284
+ const cells = row.split ("</td>\n"); // eslint-disable-line quotes
285
+ const numCells = cells.length;
286
+ if (numCells < 5) {
287
+ throw new NotSupported (error);
288
+ }
289
+ // [
290
+ // '<td>btcusd', // currency
291
+ // '<td>0.00001 BTC (1e-5)', // min order size
292
+ // '<td>0.00000001 BTC (1e-8)', // tick size
293
+ // '<td>0.01 USD', // quote currency price increment
294
+ // '</tr>'
295
+ // ]
296
+ const marketId = cells[0].replace ('<td>', '');
297
+ // const base = this.safeCurrencyCode (baseId);
298
+ const minAmountString = cells[1].replace ('<td>', '');
299
+ const minAmountParts = minAmountString.split (' ');
300
+ const minAmount = this.safeNumber (minAmountParts, 0);
301
+ const amountPrecisionString = cells[2].replace ('<td>', '');
302
+ const amountPrecisionParts = amountPrecisionString.split (' ');
303
+ const idLength = marketId.length - 0;
304
+ const startingIndex = idLength - 3;
305
+ const pricePrecisionString = cells[3].replace ('<td>', '');
306
+ const pricePrecisionParts = pricePrecisionString.split (' ');
307
+ const quoteId = this.safeStringLower (pricePrecisionParts, 1, marketId.slice (startingIndex, idLength));
308
+ const baseId = this.safeStringLower (amountPrecisionParts, 1, marketId.replace (quoteId, ''));
309
+ const base = this.safeCurrencyCode (baseId);
310
+ const quote = this.safeCurrencyCode (quoteId);
311
+ result.push ({
312
+ 'id': marketId,
313
+ 'symbol': base + '/' + quote,
314
+ 'base': base,
315
+ 'quote': quote,
316
+ 'settle': undefined,
317
+ 'baseId': baseId,
318
+ 'quoteId': quoteId,
319
+ 'settleId': undefined,
320
+ 'type': 'spot',
321
+ 'spot': true,
322
+ 'margin': false,
323
+ 'swap': false,
324
+ 'future': false,
325
+ 'option': false,
326
+ 'active': undefined,
327
+ 'contract': false,
328
+ 'linear': undefined,
329
+ 'inverse': undefined,
330
+ 'contractSize': undefined,
331
+ 'expiry': undefined,
332
+ 'expiryDatetime': undefined,
333
+ 'strike': undefined,
334
+ 'optionType': undefined,
335
+ 'precision': {
336
+ 'amount': this.safeNumber (amountPrecisionParts, 0),
337
+ 'price': this.safeNumber (pricePrecisionParts, 0),
338
+ },
339
+ 'limits': {
340
+ 'leverage': {
341
+ 'min': undefined,
342
+ 'max': undefined,
343
+ },
344
+ 'amount': {
345
+ 'min': minAmount,
346
+ 'max': undefined,
347
+ },
348
+ 'price': {
349
+ 'min': undefined,
350
+ 'max': undefined,
351
+ },
352
+ 'cost': {
353
+ 'min': undefined,
354
+ 'max': undefined,
355
+ },
356
+ },
357
+ 'info': row,
358
+ });
359
+ }
360
+ return result;
361
+ }
362
+
363
+ async fetchMarketsFromAPI (params = {}) {
364
+ const response = await this.publicGetV1Symbols (params);
365
+ const result = [];
366
+ for (let i = 0; i < response.length; i++) {
367
+ const marketId = response[i];
368
+ const market = marketId;
369
+ const idLength = marketId.length - 0;
370
+ const baseId = marketId.slice (0, idLength - 3);
371
+ const quoteId = marketId.slice (idLength - 3, idLength);
372
+ const base = this.safeCurrencyCode (baseId);
373
+ const quote = this.safeCurrencyCode (quoteId);
374
+ result.push ({
375
+ 'id': marketId,
376
+ 'symbol': base + '/' + quote,
377
+ 'base': base,
378
+ 'quote': quote,
379
+ 'settle': undefined,
380
+ 'baseId': baseId,
381
+ 'quoteId': quoteId,
382
+ 'settleId': undefined,
383
+ 'type': 'spot',
384
+ 'spot': true,
385
+ 'margin': false,
386
+ 'swap': false,
387
+ 'future': false,
388
+ 'option': false,
389
+ 'active': undefined,
390
+ 'contract': false,
391
+ 'linear': undefined,
392
+ 'inverse': undefined,
393
+ 'contractSize': undefined,
394
+ 'expiry': undefined,
395
+ 'expiryDatetime': undefined,
396
+ 'strike': undefined,
397
+ 'optionType': undefined,
398
+ 'precision': {
399
+ 'price': undefined,
400
+ 'amount': undefined,
401
+ },
402
+ 'limits': {
403
+ 'leverage': {
404
+ 'min': undefined,
405
+ 'max': undefined,
406
+ },
407
+ 'amount': {
408
+ 'min': undefined,
409
+ 'max': undefined,
410
+ },
411
+ 'price': {
412
+ 'min': undefined,
413
+ 'max': undefined,
414
+ },
415
+ 'cost': {
416
+ 'min': undefined,
417
+ 'max': undefined,
418
+ },
419
+ },
420
+ 'info': market,
421
+ });
422
+ }
423
+ return result;
424
+ }
425
+
426
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
427
+ await this.loadMarkets ();
428
+ const request = {
429
+ 'symbol': this.marketId (symbol),
430
+ };
431
+ if (limit !== undefined) {
432
+ request['limit_bids'] = limit;
433
+ request['limit_asks'] = limit;
434
+ }
435
+ const response = await this.publicGetV1BookSymbol (this.extend (request, params));
436
+ return this.parseOrderBook (response, symbol, undefined, 'bids', 'asks', 'price', 'amount');
437
+ }
438
+
439
+ async fetchTickerV1 (symbol, params = {}) {
440
+ await this.loadMarkets ();
441
+ const market = this.market (symbol);
442
+ const request = {
443
+ 'symbol': market['id'],
444
+ };
445
+ const response = await this.publicGetV1PubtickerSymbol (this.extend (request, params));
446
+ //
447
+ // {
448
+ // "bid":"9117.95",
449
+ // "ask":"9117.96",
450
+ // "volume":{
451
+ // "BTC":"1615.46861748",
452
+ // "USD":"14727307.57545006088",
453
+ // "timestamp":1594982700000
454
+ // },
455
+ // "last":"9115.23"
456
+ // }
457
+ //
458
+ return this.parseTicker (response, market);
459
+ }
460
+
461
+ async fetchTickerV2 (symbol, params = {}) {
462
+ await this.loadMarkets ();
463
+ const market = this.market (symbol);
464
+ const request = {
465
+ 'symbol': market['id'],
466
+ };
467
+ const response = await this.publicGetV2TickerSymbol (this.extend (request, params));
468
+ //
469
+ // {
470
+ // "symbol":"BTCUSD",
471
+ // "open":"9080.58",
472
+ // "high":"9184.53",
473
+ // "low":"9063.56",
474
+ // "close":"9116.08",
475
+ // // Hourly prices descending for past 24 hours
476
+ // "changes":["9117.33","9105.69","9106.23","9120.35","9098.57","9114.53","9113.55","9128.01","9113.63","9133.49","9133.49","9137.75","9126.73","9103.91","9119.33","9123.04","9124.44","9117.57","9114.22","9102.33","9076.67","9074.72","9074.97","9092.05"],
477
+ // "bid":"9115.86",
478
+ // "ask":"9115.87"
479
+ // }
480
+ //
481
+ return this.parseTicker (response, market);
482
+ }
483
+
484
+ async fetchTickerV1AndV2 (symbol, params = {}) {
485
+ const tickerA = await this.fetchTickerV1 (symbol, params);
486
+ const tickerB = await this.fetchTickerV2 (symbol, params);
487
+ return this.deepExtend (tickerA, {
488
+ 'open': tickerB['open'],
489
+ 'high': tickerB['high'],
490
+ 'low': tickerB['low'],
491
+ 'change': tickerB['change'],
492
+ 'percentage': tickerB['percentage'],
493
+ 'average': tickerB['average'],
494
+ 'info': tickerB['info'],
495
+ });
496
+ }
497
+
498
+ async fetchTicker (symbol, params = {}) {
499
+ const method = this.safeValue (this.options, 'fetchTickerMethod', 'fetchTickerV1');
500
+ return await this[method] (symbol, params);
501
+ }
502
+
503
+ parseTicker (ticker, market = undefined) {
504
+ //
505
+ // fetchTickers
506
+ //
507
+ // {
508
+ // "pair": "BATUSD",
509
+ // "price": "0.20687",
510
+ // "percentChange24h": "0.0146"
511
+ // }
512
+ //
513
+ // fetchTickerV1
514
+ //
515
+ // {
516
+ // "bid":"9117.95",
517
+ // "ask":"9117.96",
518
+ // "volume":{
519
+ // "BTC":"1615.46861748",
520
+ // "USD":"14727307.57545006088",
521
+ // "timestamp":1594982700000
522
+ // },
523
+ // "last":"9115.23"
524
+ // }
525
+ //
526
+ // fetchTickerV2
527
+ //
528
+ // {
529
+ // "symbol":"BTCUSD",
530
+ // "open":"9080.58",
531
+ // "high":"9184.53",
532
+ // "low":"9063.56",
533
+ // "close":"9116.08",
534
+ // // Hourly prices descending for past 24 hours
535
+ // "changes":["9117.33","9105.69","9106.23","9120.35","9098.57","9114.53","9113.55","9128.01","9113.63","9133.49","9133.49","9137.75","9126.73","9103.91","9119.33","9123.04","9124.44","9117.57","9114.22","9102.33","9076.67","9074.72","9074.97","9092.05"],
536
+ // "bid":"9115.86",
537
+ // "ask":"9115.87"
538
+ // }
539
+ //
540
+ const volume = this.safeValue (ticker, 'volume', {});
541
+ const timestamp = this.safeInteger (volume, 'timestamp');
542
+ let symbol = undefined;
543
+ const marketId = this.safeStringLower (ticker, 'pair');
544
+ market = this.safeMarket (marketId, market);
545
+ let baseId = undefined;
546
+ let quoteId = undefined;
547
+ let base = undefined;
548
+ let quote = undefined;
549
+ if ((marketId !== undefined) && (market === undefined)) {
550
+ const idLength = marketId.length - 0;
551
+ if (idLength === 7) {
552
+ baseId = marketId.slice (0, 4);
553
+ quoteId = marketId.slice (4, 7);
554
+ } else {
555
+ baseId = marketId.slice (0, 3);
556
+ quoteId = marketId.slice (3, 6);
557
+ }
558
+ base = this.safeCurrencyCode (baseId);
559
+ quote = this.safeCurrencyCode (quoteId);
560
+ symbol = base + '/' + quote;
561
+ }
562
+ if ((symbol === undefined) && (market !== undefined)) {
563
+ symbol = market['symbol'];
564
+ baseId = this.safeStringUpper (market, 'baseId');
565
+ quoteId = this.safeStringUpper (market, 'quoteId');
566
+ }
567
+ const price = this.safeString (ticker, 'price');
568
+ const last = this.safeString2 (ticker, 'last', 'close', price);
569
+ const percentage = this.safeString (ticker, 'percentChange24h');
570
+ const open = this.safeString (ticker, 'open');
571
+ const baseVolume = this.safeString (volume, baseId);
572
+ const quoteVolume = this.safeString (volume, quoteId);
573
+ return this.safeTicker ({
574
+ 'symbol': symbol,
575
+ 'timestamp': timestamp,
576
+ 'datetime': this.iso8601 (timestamp),
577
+ 'high': this.safeString (ticker, 'high'),
578
+ 'low': this.safeString (ticker, 'low'),
579
+ 'bid': this.safeString (ticker, 'bid'),
580
+ 'bidVolume': undefined,
581
+ 'ask': this.safeString (ticker, 'ask'),
582
+ 'askVolume': undefined,
583
+ 'vwap': undefined,
584
+ 'open': open,
585
+ 'close': last,
586
+ 'last': last,
587
+ 'previousClose': undefined, // previous day close
588
+ 'change': undefined,
589
+ 'percentage': percentage,
590
+ 'average': undefined,
591
+ 'baseVolume': baseVolume,
592
+ 'quoteVolume': quoteVolume,
593
+ 'info': ticker,
594
+ }, market, false);
595
+ }
596
+
597
+ async fetchTickers (symbols = undefined, params = {}) {
598
+ await this.loadMarkets ();
599
+ const response = await this.publicGetV1Pricefeed (params);
600
+ //
601
+ // [
602
+ // {
603
+ // "pair": "BATUSD",
604
+ // "price": "0.20687",
605
+ // "percentChange24h": "0.0146"
606
+ // },
607
+ // {
608
+ // "pair": "LINKETH",
609
+ // "price": "0.018",
610
+ // "percentChange24h": "0.0000"
611
+ // },
612
+ // ]
613
+ //
614
+ return this.parseTickers (response, symbols);
615
+ }
616
+
617
+ parseTrade (trade, market = undefined) {
618
+ //
619
+ // public fetchTrades
620
+ //
621
+ // {
622
+ // "timestamp":1601617445,
623
+ // "timestampms":1601617445144,
624
+ // "tid":14122489752,
625
+ // "price":"0.46476",
626
+ // "amount":"28.407209",
627
+ // "exchange":"gemini",
628
+ // "type":"buy"
629
+ // }
630
+ //
631
+ // private fetchTrades
632
+ //
633
+ // {
634
+ // "price":"3900.00",
635
+ // "amount":"0.00996",
636
+ // "timestamp":1638891173,
637
+ // "timestampms":1638891173518,
638
+ // "type":"Sell",
639
+ // "aggressor":false,
640
+ // "fee_currency":"EUR",
641
+ // "fee_amount":"0.00",
642
+ // "tid":73621746145,
643
+ // "order_id":"73621746059",
644
+ // "exchange":"gemini",
645
+ // "is_auction_fill":false,
646
+ // "is_clearing_fill":false,
647
+ // "symbol":"ETHEUR",
648
+ // "client_order_id":"1638891171610"
649
+ // }
650
+ //
651
+ const timestamp = this.safeInteger (trade, 'timestampms');
652
+ const id = this.safeString (trade, 'tid');
653
+ const orderId = this.safeString (trade, 'order_id');
654
+ const feeCurrencyId = this.safeString (trade, 'fee_currency');
655
+ const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
656
+ const fee = {
657
+ 'cost': this.safeString (trade, 'fee_amount'),
658
+ 'currency': feeCurrencyCode,
659
+ };
660
+ const priceString = this.safeString (trade, 'price');
661
+ const amountString = this.safeString (trade, 'amount');
662
+ const side = this.safeStringLower (trade, 'type');
663
+ const symbol = this.safeSymbol (undefined, market);
664
+ return this.safeTrade ({
665
+ 'id': id,
666
+ 'order': orderId,
667
+ 'info': trade,
668
+ 'timestamp': timestamp,
669
+ 'datetime': this.iso8601 (timestamp),
670
+ 'symbol': symbol,
671
+ 'type': undefined,
672
+ 'side': side,
673
+ 'takerOrMaker': undefined,
674
+ 'price': priceString,
675
+ 'cost': undefined,
676
+ 'amount': amountString,
677
+ 'fee': fee,
678
+ }, market);
679
+ }
680
+
681
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
682
+ await this.loadMarkets ();
683
+ const market = this.market (symbol);
684
+ const request = {
685
+ 'symbol': market['id'],
686
+ };
687
+ const response = await this.publicGetV1TradesSymbol (this.extend (request, params));
688
+ //
689
+ // [
690
+ // {
691
+ // "timestamp":1601617445,
692
+ // "timestampms":1601617445144,
693
+ // "tid":14122489752,
694
+ // "price":"0.46476",
695
+ // "amount":"28.407209",
696
+ // "exchange":"gemini",
697
+ // "type":"buy"
698
+ // },
699
+ // ]
700
+ //
701
+ return this.parseTrades (response, market, since, limit);
702
+ }
703
+
704
+ parseBalance (response) {
705
+ const result = { 'info': response };
706
+ for (let i = 0; i < response.length; i++) {
707
+ const balance = response[i];
708
+ const currencyId = this.safeString (balance, 'currency');
709
+ const code = this.safeCurrencyCode (currencyId);
710
+ const account = this.account ();
711
+ account['free'] = this.safeString (balance, 'available');
712
+ account['total'] = this.safeString (balance, 'amount');
713
+ result[code] = account;
714
+ }
715
+ return this.safeBalance (result);
716
+ }
717
+
718
+ async fetchTradingFees (params = {}) {
719
+ await this.loadMarkets ();
720
+ const response = await this.privatePostV1Notionalvolume (params);
721
+ //
722
+ // {
723
+ // "web_maker_fee_bps": 25,
724
+ // "web_taker_fee_bps": 35,
725
+ // "web_auction_fee_bps": 25,
726
+ // "api_maker_fee_bps": 10,
727
+ // "api_taker_fee_bps": 35,
728
+ // "api_auction_fee_bps": 20,
729
+ // "fix_maker_fee_bps": 10,
730
+ // "fix_taker_fee_bps": 35,
731
+ // "fix_auction_fee_bps": 20,
732
+ // "block_maker_fee_bps": 0,
733
+ // "block_taker_fee_bps": 50,
734
+ // "notional_30d_volume": 150.00,
735
+ // "last_updated_ms": 1551371446000,
736
+ // "date": "2019-02-28",
737
+ // "notional_1d_volume": [
738
+ // {
739
+ // "date": "2019-02-22",
740
+ // "notional_volume": 75.00
741
+ // },
742
+ // {
743
+ // "date": "2019-02-14",
744
+ // "notional_volume": 75.00
745
+ // }
746
+ // ]
747
+ // }
748
+ //
749
+ const makerBps = this.safeString (response, 'api_maker_fee_bps');
750
+ const takerBps = this.safeString (response, 'api_taker_fee_bps');
751
+ const makerString = Precise.stringDiv (makerBps, '10000');
752
+ const takerString = Precise.stringDiv (takerBps, '10000');
753
+ const maker = this.parseNumber (makerString);
754
+ const taker = this.parseNumber (takerString);
755
+ const result = {};
756
+ for (let i = 0; i < this.symbols.length; i++) {
757
+ const symbol = this.symbols[i];
758
+ result[symbol] = {
759
+ 'info': response,
760
+ 'symbol': symbol,
761
+ 'maker': maker,
762
+ 'taker': taker,
763
+ 'percentage': true,
764
+ 'tierBased': true,
765
+ };
766
+ }
767
+ return result;
768
+ }
769
+
770
+ async fetchBalance (params = {}) {
771
+ await this.loadMarkets ();
772
+ const response = await this.privatePostV1Balances (params);
773
+ return this.parseBalance (response);
774
+ }
775
+
776
+ parseOrder (order, market = undefined) {
777
+ //
778
+ // createOrder (private)
779
+ //
780
+ // {
781
+ // "order_id":"106027397702",
782
+ // "id":"106027397702",
783
+ // "symbol":"etheur",
784
+ // "exchange":"gemini",
785
+ // "avg_execution_price":"2877.48",
786
+ // "side":"sell",
787
+ // "type":"exchange limit",
788
+ // "timestamp":"1650398122",
789
+ // "timestampms":1650398122308,
790
+ // "is_live":false,
791
+ // "is_cancelled":false,
792
+ // "is_hidden":false,
793
+ // "was_forced":false,
794
+ // "executed_amount":"0.014434",
795
+ // "client_order_id":"1650398121695",
796
+ // "options":[],
797
+ // "price":"2800.00",
798
+ // "original_amount":"0.014434",
799
+ // "remaining_amount":"0"
800
+ // }
801
+ //
802
+ // fetchOrder (private)
803
+ //
804
+ // {
805
+ // "order_id":"106028543717",
806
+ // "id":"106028543717",
807
+ // "symbol":"etheur",
808
+ // "exchange":"gemini",
809
+ // "avg_execution_price":"0.00",
810
+ // "side":"buy",
811
+ // "type":"exchange limit",
812
+ // "timestamp":"1650398446",
813
+ // "timestampms":1650398446375,
814
+ // "is_live":true,
815
+ // "is_cancelled":false,
816
+ // "is_hidden":false,
817
+ // "was_forced":false,
818
+ // "executed_amount":"0",
819
+ // "client_order_id":"1650398445709",
820
+ // "options":[],
821
+ // "price":"2000.00",
822
+ // "original_amount":"0.01",
823
+ // "remaining_amount":"0.01"
824
+ // }
825
+ //
826
+ // fetchOpenOrders (private)
827
+ //
828
+ // {
829
+ // "order_id":"106028543717",
830
+ // "id":"106028543717",
831
+ // "symbol":"etheur",
832
+ // "exchange":"gemini",
833
+ // "avg_execution_price":"0.00",
834
+ // "side":"buy",
835
+ // "type":"exchange limit",
836
+ // "timestamp":"1650398446",
837
+ // "timestampms":1650398446375,
838
+ // "is_live":true,
839
+ // "is_cancelled":false,
840
+ // "is_hidden":false,
841
+ // "was_forced":false,
842
+ // "executed_amount":"0",
843
+ // "client_order_id":"1650398445709",
844
+ // "options":[],
845
+ // "price":"2000.00",
846
+ // "original_amount":"0.01",
847
+ // "remaining_amount":"0.01"
848
+ // }
849
+ //
850
+ // cancelOrder (private)
851
+ //
852
+ // {
853
+ // "order_id":"106028543717",
854
+ // "id":"106028543717",
855
+ // "symbol":"etheur",
856
+ // "exchange":"gemini",
857
+ // "avg_execution_price":"0.00",
858
+ // "side":"buy",
859
+ // "type":"exchange limit",
860
+ // "timestamp":"1650398446",
861
+ // "timestampms":1650398446375,
862
+ // "is_live":false,
863
+ // "is_cancelled":true,
864
+ // "is_hidden":false,
865
+ // "was_forced":false,
866
+ // "executed_amount":"0",
867
+ // "client_order_id":"1650398445709",
868
+ // "reason":"Requested",
869
+ // "options":[],
870
+ // "price":"2000.00",
871
+ // "original_amount":"0.01",
872
+ // "remaining_amount":"0.01"
873
+ // }
874
+ //
875
+ const timestamp = this.safeInteger (order, 'timestampms');
876
+ const amount = this.safeString (order, 'original_amount');
877
+ const remaining = this.safeString (order, 'remaining_amount');
878
+ const filled = this.safeString (order, 'executed_amount');
879
+ let status = 'closed';
880
+ if (order['is_live']) {
881
+ status = 'open';
882
+ }
883
+ if (order['is_cancelled']) {
884
+ status = 'canceled';
885
+ }
886
+ const price = this.safeString (order, 'price');
887
+ const average = this.safeString (order, 'avg_execution_price');
888
+ let type = this.safeString (order, 'type');
889
+ if (type === 'exchange limit') {
890
+ type = 'limit';
891
+ } else if (type === 'market buy' || type === 'market sell') {
892
+ type = 'market';
893
+ } else {
894
+ type = order['type'];
895
+ }
896
+ const fee = undefined;
897
+ const marketId = this.safeString (order, 'symbol');
898
+ const symbol = this.safeSymbol (marketId, market);
899
+ const id = this.safeString (order, 'order_id');
900
+ const side = this.safeStringLower (order, 'side');
901
+ const clientOrderId = this.safeString (order, 'client_order_id');
902
+ const optionsArray = this.safeValue (order, 'options', []);
903
+ const option = this.safeString (optionsArray, 0);
904
+ let timeInForce = 'GTC';
905
+ let postOnly = false;
906
+ if (option !== undefined) {
907
+ if (option === 'immediate-or-cancel') {
908
+ timeInForce = 'IOC';
909
+ } else if (option === 'fill-or-kill') {
910
+ timeInForce = 'FOK';
911
+ } else if (option === 'maker-or-cancel') {
912
+ timeInForce = 'PO';
913
+ postOnly = true;
914
+ }
915
+ }
916
+ return this.safeOrder ({
917
+ 'id': id,
918
+ 'clientOrderId': clientOrderId,
919
+ 'info': order,
920
+ 'timestamp': timestamp,
921
+ 'datetime': this.iso8601 (timestamp),
922
+ 'lastTradeTimestamp': undefined,
923
+ 'status': status,
924
+ 'symbol': symbol,
925
+ 'type': type,
926
+ 'timeInForce': timeInForce, // default set to GTC
927
+ 'postOnly': postOnly,
928
+ 'side': side,
929
+ 'price': price,
930
+ 'stopPrice': undefined,
931
+ 'average': average,
932
+ 'cost': undefined,
933
+ 'amount': amount,
934
+ 'filled': filled,
935
+ 'remaining': remaining,
936
+ 'fee': fee,
937
+ 'trades': undefined,
938
+ }, market);
939
+ }
940
+
941
+ async fetchOrder (id, symbol = undefined, params = {}) {
942
+ await this.loadMarkets ();
943
+ const request = {
944
+ 'order_id': id,
945
+ };
946
+ const response = await this.privatePostV1OrderStatus (this.extend (request, params));
947
+ //
948
+ // {
949
+ // "order_id":"106028543717",
950
+ // "id":"106028543717",
951
+ // "symbol":"etheur",
952
+ // "exchange":"gemini",
953
+ // "avg_execution_price":"0.00",
954
+ // "side":"buy",
955
+ // "type":"exchange limit",
956
+ // "timestamp":"1650398446",
957
+ // "timestampms":1650398446375,
958
+ // "is_live":true,
959
+ // "is_cancelled":false,
960
+ // "is_hidden":false,
961
+ // "was_forced":false,
962
+ // "executed_amount":"0",
963
+ // "client_order_id":"1650398445709",
964
+ // "options":[],
965
+ // "price":"2000.00",
966
+ // "original_amount":"0.01",
967
+ // "remaining_amount":"0.01"
968
+ // }
969
+ //
970
+ return this.parseOrder (response);
971
+ }
972
+
973
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
974
+ await this.loadMarkets ();
975
+ const response = await this.privatePostV1Orders (); // takes no params
976
+ //
977
+ // [
978
+ // {
979
+ // "order_id":"106028543717",
980
+ // "id":"106028543717",
981
+ // "symbol":"etheur",
982
+ // "exchange":"gemini",
983
+ // "avg_execution_price":"0.00",
984
+ // "side":"buy",
985
+ // "type":"exchange limit",
986
+ // "timestamp":"1650398446",
987
+ // "timestampms":1650398446375,
988
+ // "is_live":true,
989
+ // "is_cancelled":false,
990
+ // "is_hidden":false,
991
+ // "was_forced":false,
992
+ // "executed_amount":"0",
993
+ // "client_order_id":"1650398445709",
994
+ // "options":[],
995
+ // "price":"2000.00",
996
+ // "original_amount":"0.01",
997
+ // "remaining_amount":"0.01"
998
+ // }
999
+ // ]
1000
+ //
1001
+ let market = undefined;
1002
+ if (symbol !== undefined) {
1003
+ market = this.market (symbol); // throws on non-existent symbol
1004
+ }
1005
+ return this.parseOrders (response, market, since, limit);
1006
+ }
1007
+
1008
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
1009
+ await this.loadMarkets ();
1010
+ if (type === 'market') {
1011
+ throw new ExchangeError (this.id + ' createOrder() allows limit orders only');
1012
+ }
1013
+ let clientOrderId = this.safeString2 (params, 'clientOrderId', 'client_order_id');
1014
+ params = this.omit (params, [ 'clientOrderId', 'client_order_id' ]);
1015
+ if (clientOrderId === undefined) {
1016
+ clientOrderId = this.nonce ();
1017
+ }
1018
+ const amountString = this.amountToPrecision (symbol, amount);
1019
+ const priceString = this.priceToPrecision (symbol, price);
1020
+ const request = {
1021
+ 'client_order_id': clientOrderId.toString (),
1022
+ 'symbol': this.marketId (symbol),
1023
+ 'amount': amountString,
1024
+ 'price': priceString,
1025
+ 'side': side,
1026
+ 'type': 'exchange limit', // gemini allows limit orders only
1027
+ // 'options': [], one of: maker-or-cancel, immediate-or-cancel, fill-or-kill, auction-only, indication-of-interest
1028
+ };
1029
+ type = this.safeString (params, 'type', type);
1030
+ params = this.omit (params, 'type');
1031
+ const rawStopPrice = this.safeString2 (params, 'stop_price', 'stopPrice');
1032
+ params = this.omit (params, [ 'stop_price', 'stopPrice', 'type' ]);
1033
+ if (type === 'stopLimit') {
1034
+ throw new ArgumentsRequired (this.id + ' createOrder() requires a stopPrice parameter or a stop_price parameter for ' + type + ' orders');
1035
+ }
1036
+ if (rawStopPrice !== undefined) {
1037
+ request['stop_price'] = this.priceToPrecision (symbol, rawStopPrice);
1038
+ request['type'] = 'exchange stop limit';
1039
+ } else {
1040
+ // No options can be applied to stop-limit orders at this time.
1041
+ const timeInForce = this.safeString (params, 'timeInForce');
1042
+ params = this.omit (params, 'timeInForce');
1043
+ if (timeInForce !== undefined) {
1044
+ if ((timeInForce === 'IOC') || (timeInForce === 'immediate-or-cancel')) {
1045
+ request['options'] = [ 'immediate-or-cancel' ];
1046
+ } else if ((timeInForce === 'FOK') || (timeInForce === 'fill-or-kill')) {
1047
+ request['options'] = [ 'fill-or-kill' ];
1048
+ } else if (timeInForce === 'PO') {
1049
+ request['options'] = [ 'maker-or-cancel' ];
1050
+ }
1051
+ }
1052
+ const postOnly = this.safeValue (params, 'postOnly', false);
1053
+ params = this.omit (params, 'postOnly');
1054
+ if (postOnly) {
1055
+ request['options'] = [ 'maker-or-cancel' ];
1056
+ }
1057
+ // allowing override for auction-only and indication-of-interest order options
1058
+ const options = this.safeString (params, 'options');
1059
+ if (options !== undefined) {
1060
+ request['options'] = [ options ];
1061
+ }
1062
+ }
1063
+ const response = await this.privatePostV1OrderNew (this.extend (request, params));
1064
+ //
1065
+ // {
1066
+ // "order_id":"106027397702",
1067
+ // "id":"106027397702",
1068
+ // "symbol":"etheur",
1069
+ // "exchange":"gemini",
1070
+ // "avg_execution_price":"2877.48",
1071
+ // "side":"sell",
1072
+ // "type":"exchange limit",
1073
+ // "timestamp":"1650398122",
1074
+ // "timestampms":1650398122308,
1075
+ // "is_live":false,
1076
+ // "is_cancelled":false,
1077
+ // "is_hidden":false,
1078
+ // "was_forced":false,
1079
+ // "executed_amount":"0.014434",
1080
+ // "client_order_id":"1650398121695",
1081
+ // "options":[],
1082
+ // "price":"2800.00",
1083
+ // "original_amount":"0.014434",
1084
+ // "remaining_amount":"0"
1085
+ // }
1086
+ //
1087
+ return this.parseOrder (response);
1088
+ }
1089
+
1090
+ async cancelOrder (id, symbol = undefined, params = {}) {
1091
+ await this.loadMarkets ();
1092
+ const request = {
1093
+ 'order_id': id,
1094
+ };
1095
+ const response = await this.privatePostV1OrderCancel (this.extend (request, params));
1096
+ //
1097
+ // {
1098
+ // "order_id":"106028543717",
1099
+ // "id":"106028543717",
1100
+ // "symbol":"etheur",
1101
+ // "exchange":"gemini",
1102
+ // "avg_execution_price":"0.00",
1103
+ // "side":"buy",
1104
+ // "type":"exchange limit",
1105
+ // "timestamp":"1650398446",
1106
+ // "timestampms":1650398446375,
1107
+ // "is_live":false,
1108
+ // "is_cancelled":true,
1109
+ // "is_hidden":false,
1110
+ // "was_forced":false,
1111
+ // "executed_amount":"0",
1112
+ // "client_order_id":"1650398445709",
1113
+ // "reason":"Requested",
1114
+ // "options":[],
1115
+ // "price":"2000.00",
1116
+ // "original_amount":"0.01",
1117
+ // "remaining_amount":"0.01"
1118
+ // }
1119
+ //
1120
+ return this.parseOrder (response);
1121
+ }
1122
+
1123
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
1124
+ if (symbol === undefined) {
1125
+ throw new ArgumentsRequired (this.id + ' fetchMyTrades() requires a symbol argument');
1126
+ }
1127
+ await this.loadMarkets ();
1128
+ const market = this.market (symbol);
1129
+ const request = {
1130
+ 'symbol': market['id'],
1131
+ };
1132
+ if (limit !== undefined) {
1133
+ request['limit_trades'] = limit;
1134
+ }
1135
+ if (since !== undefined) {
1136
+ request['timestamp'] = parseInt (since / 1000);
1137
+ }
1138
+ const response = await this.privatePostV1Mytrades (this.extend (request, params));
1139
+ return this.parseTrades (response, market, since, limit);
1140
+ }
1141
+
1142
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
1143
+ [ tag, params ] = this.handleWithdrawTagAndParams (tag, params);
1144
+ this.checkAddress (address);
1145
+ await this.loadMarkets ();
1146
+ const currency = this.currency (code);
1147
+ const request = {
1148
+ 'currency': currency['id'],
1149
+ 'amount': amount,
1150
+ 'address': address,
1151
+ };
1152
+ const response = await this.privatePostV1WithdrawCurrency (this.extend (request, params));
1153
+ //
1154
+ // for BTC
1155
+ // {
1156
+ // "address":"mi98Z9brJ3TgaKsmvXatuRahbFRUFKRUdR",
1157
+ // "amount":"1",
1158
+ // "withdrawalId":"02176a83-a6b1-4202-9b85-1c1c92dd25c4",
1159
+ // "message":"You have requested a transfer of 1 BTC to mi98Z9brJ3TgaKsmvXatuRahbFRUFKRUdR. This withdrawal will be sent to the blockchain within the next 60 seconds."
1160
+ // }
1161
+ //
1162
+ // for ETH
1163
+ // {
1164
+ // "address":"0xA63123350Acc8F5ee1b1fBd1A6717135e82dBd28",
1165
+ // "amount":"2.34567",
1166
+ // "txHash":"0x28267179f92926d85c5516bqc063b2631935573d8915258e95d9572eedcc8cc"
1167
+ // }
1168
+ //
1169
+ // for error (other variations of error messages are also expected)
1170
+ // {
1171
+ // "result":"error",
1172
+ // "reason":"CryptoAddressWhitelistsNotEnabled",
1173
+ // "message":"Cryptocurrency withdrawal address whitelists are not enabled for account 24. Please contact support@gemini.com for information on setting up a withdrawal address whitelist."
1174
+ // }
1175
+ //
1176
+ const result = this.safeString (response, 'result');
1177
+ if (result === 'error') {
1178
+ throw new ExchangeError (this.id + ' withdraw() failed: ' + this.json (response));
1179
+ }
1180
+ return this.parseTransaction (response, currency);
1181
+ }
1182
+
1183
+ nonce () {
1184
+ return this.milliseconds ();
1185
+ }
1186
+
1187
+ async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
1188
+ await this.loadMarkets ();
1189
+ const request = {};
1190
+ if (limit !== undefined) {
1191
+ request['limit_transfers'] = limit;
1192
+ }
1193
+ if (since !== undefined) {
1194
+ request['timestamp'] = since;
1195
+ }
1196
+ const response = await this.privatePostV1Transfers (this.extend (request, params));
1197
+ return this.parseTransactions (response);
1198
+ }
1199
+
1200
+ parseTransaction (transaction, currency = undefined) {
1201
+ //
1202
+ // withdraw
1203
+ //
1204
+ // for BTC
1205
+ // {
1206
+ // "address":"mi98Z9brJ3TgaKsmvXatuRahbFRUFKRUdR",
1207
+ // "amount":"1",
1208
+ // "withdrawalId":"02176a83-a6b1-4202-9b85-1c1c92dd25c4",
1209
+ // "message":"You have requested a transfer of 1 BTC to mi98Z9brJ3TgaKsmvXatuRahbFRUFKRUdR. This withdrawal will be sent to the blockchain within the next 60 seconds."
1210
+ // }
1211
+ //
1212
+ // for ETH
1213
+ // {
1214
+ // "address":"0xA63123350Acc8F5ee1b1fBd1A6717135e82dBd28",
1215
+ // "amount":"2.34567",
1216
+ // "txHash":"0x28267179f92926d85c5516bqc063b2631935573d8915258e95d9572eedcc8cc"
1217
+ // }
1218
+ //
1219
+ const timestamp = this.safeInteger (transaction, 'timestampms');
1220
+ const currencyId = this.safeString (transaction, 'currency');
1221
+ const code = this.safeCurrencyCode (currencyId, currency);
1222
+ const address = this.safeString (transaction, 'destination');
1223
+ const type = this.safeStringLower (transaction, 'type');
1224
+ // if status field is available, then it's complete
1225
+ const statusRaw = this.safeString (transaction, 'status');
1226
+ let fee = undefined;
1227
+ const feeAmount = this.safeNumber (transaction, 'feeAmount');
1228
+ if (feeAmount !== undefined) {
1229
+ fee = {
1230
+ 'cost': feeAmount,
1231
+ 'currency': code,
1232
+ };
1233
+ }
1234
+ return {
1235
+ 'info': transaction,
1236
+ 'id': this.safeString2 (transaction, 'eid', 'withdrawalId'),
1237
+ 'txid': this.safeString (transaction, 'txHash'),
1238
+ 'timestamp': timestamp,
1239
+ 'datetime': this.iso8601 (timestamp),
1240
+ 'network': undefined,
1241
+ 'address': address,
1242
+ 'addressTo': undefined,
1243
+ 'addressFrom': undefined,
1244
+ 'tag': undefined, // or is it defined?
1245
+ 'tagTo': undefined,
1246
+ 'tagFrom': undefined,
1247
+ 'type': type, // direction of the transaction, ('deposit' | 'withdraw')
1248
+ 'amount': this.safeNumber (transaction, 'amount'),
1249
+ 'currency': code,
1250
+ 'status': this.parseTransactionStatus (statusRaw),
1251
+ 'updated': undefined,
1252
+ 'fee': fee,
1253
+ };
1254
+ }
1255
+
1256
+ parseTransactionStatus (status) {
1257
+ const statuses = {
1258
+ 'Advanced': 'ok',
1259
+ 'Complete': 'ok',
1260
+ };
1261
+ return this.safeString (statuses, status, status);
1262
+ }
1263
+
1264
+ parseDepositAddress (depositAddress, currency = undefined) {
1265
+ //
1266
+ // {
1267
+ // address: "0xed6494Fe7c1E56d1bd6136e89268C51E32d9708B",
1268
+ // timestamp: "1636813923098",
1269
+ // addressVersion: "eV1" }
1270
+ // }
1271
+ //
1272
+ const address = this.safeString (depositAddress, 'address');
1273
+ return {
1274
+ 'currency': currency,
1275
+ 'network': undefined,
1276
+ 'address': address,
1277
+ 'tag': undefined,
1278
+ 'info': depositAddress,
1279
+ };
1280
+ }
1281
+
1282
+ async fetchDepositAddressesByNetwork (code, params = {}) {
1283
+ await this.loadMarkets ();
1284
+ const network = this.safeString (params, 'network');
1285
+ if (network === undefined) {
1286
+ throw new ArgumentsRequired (this.id + ' fetchDepositAddressesByNetwork() requires a network parameter');
1287
+ }
1288
+ params = this.omit (params, 'network');
1289
+ const networks = this.safeValue (this.options, 'networks', {});
1290
+ const networkId = this.safeString (networks, network, network);
1291
+ const networkIds = this.safeValue (this.options, 'networkIds', {});
1292
+ const networkCode = this.safeString (networkIds, networkId, network);
1293
+ const request = {
1294
+ 'network': networkId,
1295
+ };
1296
+ const response = await this.privatePostV1AddressesNetwork (this.extend (request, params));
1297
+ const results = this.parseDepositAddresses (response, [ code ], false, { 'network': networkCode, 'currency': code });
1298
+ return this.groupBy (results, 'network');
1299
+ }
1300
+
1301
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
1302
+ let url = '/' + this.implodeParams (path, params);
1303
+ const query = this.omit (params, this.extractParams (path));
1304
+ if (api === 'private') {
1305
+ this.checkRequiredCredentials ();
1306
+ const apiKey = this.apiKey;
1307
+ if (apiKey.indexOf ('account') < 0) {
1308
+ throw new AuthenticationError (this.id + ' sign() requires an account-key, master-keys are not-supported');
1309
+ }
1310
+ const nonce = this.nonce ();
1311
+ const request = this.extend ({
1312
+ 'request': url,
1313
+ 'nonce': nonce,
1314
+ }, query);
1315
+ let payload = this.json (request);
1316
+ payload = this.stringToBase64 (payload);
1317
+ const signature = this.hmac (payload, this.encode (this.secret), 'sha384');
1318
+ headers = {
1319
+ 'Content-Type': 'text/plain',
1320
+ 'X-GEMINI-APIKEY': this.apiKey,
1321
+ 'X-GEMINI-PAYLOAD': this.decode (payload),
1322
+ 'X-GEMINI-SIGNATURE': signature,
1323
+ };
1324
+ } else {
1325
+ if (Object.keys (query).length) {
1326
+ url += '?' + this.urlencode (query);
1327
+ }
1328
+ }
1329
+ url = this.urls['api'][api] + url;
1330
+ if ((method === 'POST') || (method === 'DELETE')) {
1331
+ body = this.json (query);
1332
+ }
1333
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
1334
+ }
1335
+
1336
+ handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
1337
+ if (response === undefined) {
1338
+ if (typeof body === 'string') {
1339
+ const feedback = this.id + ' ' + body;
1340
+ this.throwBroadlyMatchedException (this.exceptions['broad'], body, feedback);
1341
+ }
1342
+ return; // fallback to default error handler
1343
+ }
1344
+ //
1345
+ // {
1346
+ // "result": "error",
1347
+ // "reason": "BadNonce",
1348
+ // "message": "Out-of-sequence nonce <1234> precedes previously used nonce <2345>"
1349
+ // }
1350
+ //
1351
+ const result = this.safeString (response, 'result');
1352
+ if (result === 'error') {
1353
+ const reason = this.safeString (response, 'reason');
1354
+ const message = this.safeString (response, 'message');
1355
+ const feedback = this.id + ' ' + message;
1356
+ this.throwExactlyMatchedException (this.exceptions['exact'], reason, feedback);
1357
+ this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
1358
+ this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
1359
+ throw new ExchangeError (feedback); // unknown message
1360
+ }
1361
+ }
1362
+
1363
+ async createDepositAddress (code, params = {}) {
1364
+ await this.loadMarkets ();
1365
+ const currency = this.currency (code);
1366
+ const request = {
1367
+ 'currency': currency['id'],
1368
+ };
1369
+ const response = await this.privatePostV1DepositCurrencyNewAddress (this.extend (request, params));
1370
+ const address = this.safeString (response, 'address');
1371
+ this.checkAddress (address);
1372
+ return {
1373
+ 'currency': code,
1374
+ 'address': address,
1375
+ 'tag': undefined,
1376
+ 'info': response,
1377
+ };
1378
+ }
1379
+
1380
+ async fetchOHLCV (symbol, timeframe = '5m', since = undefined, limit = undefined, params = {}) {
1381
+ await this.loadMarkets ();
1382
+ const market = this.market (symbol);
1383
+ const request = {
1384
+ 'timeframe': this.timeframes[timeframe],
1385
+ 'symbol': market['id'],
1386
+ };
1387
+ const response = await this.publicGetV2CandlesSymbolTimeframe (this.extend (request, params));
1388
+ //
1389
+ // [
1390
+ // [1591515000000,0.02509,0.02509,0.02509,0.02509,0],
1391
+ // [1591514700000,0.02503,0.02509,0.02503,0.02509,44.6405],
1392
+ // [1591514400000,0.02503,0.02503,0.02503,0.02503,0],
1393
+ // ]
1394
+ //
1395
+ return this.parseOHLCVs (response, market, timeframe, since, limit);
1396
+ }
1397
+ };