ccxt 4.3.69 → 4.3.71

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 (187) hide show
  1. package/README.md +7 -6
  2. package/dist/ccxt.browser.min.js +13 -10
  3. package/dist/cjs/ccxt.js +8 -1
  4. package/dist/cjs/src/abstract/paradex.js +9 -0
  5. package/dist/cjs/src/ascendex.js +1 -1
  6. package/dist/cjs/src/base/Exchange.js +55 -0
  7. package/dist/cjs/src/binance.js +1 -1
  8. package/dist/cjs/src/blofin.js +63 -6
  9. package/dist/cjs/src/bybit.js +1 -1
  10. package/dist/cjs/src/coinbaseinternational.js +168 -2
  11. package/dist/cjs/src/cryptocom.js +9 -1
  12. package/dist/cjs/src/hitbtc.js +1 -1
  13. package/dist/cjs/src/paradex.js +2075 -0
  14. package/dist/cjs/src/poloniex.js +1 -0
  15. package/dist/cjs/src/pro/bequant.js +4 -0
  16. package/dist/cjs/src/pro/blofin.js +665 -0
  17. package/dist/cjs/src/pro/coinbaseinternational.js +154 -9
  18. package/dist/cjs/src/pro/cryptocom.js +3 -1
  19. package/dist/cjs/src/pro/hitbtc.js +26 -8
  20. package/dist/cjs/src/pro/okx.js +7 -0
  21. package/dist/cjs/src/pro/paradex.js +365 -0
  22. package/dist/cjs/src/pro/poloniex.js +37 -12
  23. package/dist/cjs/src/pro/woo.js +5 -4
  24. package/dist/cjs/src/static_dependencies/noble-curves/abstract/poseidon.js +100 -0
  25. package/dist/cjs/src/static_dependencies/noble-curves/abstract/weierstrass.js +1 -0
  26. package/dist/cjs/src/static_dependencies/scure-starknet/index.js +284 -0
  27. package/dist/cjs/src/static_dependencies/starknet/constants.js +60 -0
  28. package/dist/cjs/src/static_dependencies/starknet/types/calldata.js +26 -0
  29. package/dist/cjs/src/static_dependencies/starknet/types/lib/contract/abi.js +8 -0
  30. package/dist/cjs/src/static_dependencies/starknet/types/lib/contract/index.js +13 -0
  31. package/dist/cjs/src/static_dependencies/starknet/types/lib/index.js +56 -0
  32. package/dist/cjs/src/static_dependencies/starknet/types/typedData.js +19 -0
  33. package/dist/cjs/src/static_dependencies/starknet/utils/assert.js +15 -0
  34. package/dist/cjs/src/static_dependencies/starknet/utils/cairoDataTypes/felt.js +44 -0
  35. package/dist/cjs/src/static_dependencies/starknet/utils/cairoDataTypes/uint256.js +122 -0
  36. package/dist/cjs/src/static_dependencies/starknet/utils/cairoDataTypes/uint512.js +137 -0
  37. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/byteArray.js +61 -0
  38. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/cairo.js +218 -0
  39. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/enum/CairoCustomEnum.js +57 -0
  40. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/enum/CairoOption.js +64 -0
  41. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/enum/CairoResult.js +63 -0
  42. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/formatter.js +66 -0
  43. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/index.js +281 -0
  44. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/parser/index.js +33 -0
  45. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/parser/parser-0-1.1.0.js +37 -0
  46. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/parser/parser-2.0.0.js +40 -0
  47. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/propertyOrder.js +156 -0
  48. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/requestParser.js +250 -0
  49. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/responseParser.js +215 -0
  50. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/tuple.js +112 -0
  51. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/validate.js +206 -0
  52. package/dist/cjs/src/static_dependencies/starknet/utils/encode.js +58 -0
  53. package/dist/cjs/src/static_dependencies/starknet/utils/hash/classHash.js +57 -0
  54. package/dist/cjs/src/static_dependencies/starknet/utils/merkle.js +76 -0
  55. package/dist/cjs/src/static_dependencies/starknet/utils/num.js +92 -0
  56. package/dist/cjs/src/static_dependencies/starknet/utils/selector.js +48 -0
  57. package/dist/cjs/src/static_dependencies/starknet/utils/shortString.js +101 -0
  58. package/dist/cjs/src/static_dependencies/starknet/utils/typedData.js +334 -0
  59. package/dist/cjs/src/woo.js +4 -2
  60. package/js/ccxt.d.ts +11 -2
  61. package/js/ccxt.js +8 -2
  62. package/js/src/abstract/coinbaseinternational.d.ts +1 -1
  63. package/js/src/abstract/paradex.d.ts +43 -0
  64. package/js/src/abstract/paradex.js +11 -0
  65. package/js/src/ascendex.js +1 -1
  66. package/js/src/base/Exchange.d.ts +8 -0
  67. package/js/src/base/Exchange.js +51 -0
  68. package/js/src/binance.js +1 -1
  69. package/js/src/blofin.d.ts +1 -1
  70. package/js/src/blofin.js +63 -6
  71. package/js/src/bybit.js +1 -1
  72. package/js/src/coinbaseinternational.d.ts +6 -1
  73. package/js/src/coinbaseinternational.js +168 -2
  74. package/js/src/cryptocom.js +10 -2
  75. package/js/src/hitbtc.js +1 -1
  76. package/js/src/paradex.d.ts +76 -0
  77. package/js/src/paradex.js +2075 -0
  78. package/js/src/poloniex.js +1 -0
  79. package/js/src/pro/bequant.js +4 -0
  80. package/js/src/pro/blofin.d.ts +39 -0
  81. package/js/src/pro/blofin.js +668 -0
  82. package/js/src/pro/coinbaseinternational.d.ts +5 -1
  83. package/js/src/pro/coinbaseinternational.js +155 -10
  84. package/js/src/pro/cryptocom.js +4 -2
  85. package/js/src/pro/hitbtc.d.ts +1 -1
  86. package/js/src/pro/hitbtc.js +26 -8
  87. package/js/src/pro/okx.js +7 -0
  88. package/js/src/pro/paradex.d.ts +15 -0
  89. package/js/src/pro/paradex.js +366 -0
  90. package/js/src/pro/poloniex.js +37 -12
  91. package/js/src/pro/woo.js +5 -4
  92. package/js/src/static_dependencies/noble-curves/abstract/weierstrass.d.ts +24 -0
  93. package/js/src/static_dependencies/noble-curves/abstract/weierstrass.js +1 -1
  94. package/js/src/static_dependencies/scure-starknet/index.d.ts +79 -0
  95. package/js/src/static_dependencies/scure-starknet/index.js +323 -0
  96. package/js/src/static_dependencies/starknet/constants.d.ts +61 -0
  97. package/js/src/static_dependencies/starknet/constants.js +67 -0
  98. package/js/src/static_dependencies/starknet/index.d.ts +7 -0
  99. package/js/src/static_dependencies/starknet/index.js +50 -0
  100. package/js/src/static_dependencies/starknet/types/cairoEnum.d.ts +2 -0
  101. package/js/src/static_dependencies/starknet/types/cairoEnum.js +7 -0
  102. package/js/src/static_dependencies/starknet/types/calldata.d.ts +19 -0
  103. package/js/src/static_dependencies/starknet/types/calldata.js +28 -0
  104. package/js/src/static_dependencies/starknet/types/index.d.ts +13 -0
  105. package/js/src/static_dependencies/starknet/types/index.js +16 -0
  106. package/js/src/static_dependencies/starknet/types/lib/contract/abi.d.ts +71 -0
  107. package/js/src/static_dependencies/starknet/types/lib/contract/abi.js +13 -0
  108. package/js/src/static_dependencies/starknet/types/lib/contract/index.d.ts +24 -0
  109. package/js/src/static_dependencies/starknet/types/lib/contract/index.js +16 -0
  110. package/js/src/static_dependencies/starknet/types/lib/contract/legacy.d.ts +33 -0
  111. package/js/src/static_dependencies/starknet/types/lib/contract/legacy.js +7 -0
  112. package/js/src/static_dependencies/starknet/types/lib/contract/sierra.d.ts +52 -0
  113. package/js/src/static_dependencies/starknet/types/lib/contract/sierra.js +7 -0
  114. package/js/src/static_dependencies/starknet/types/lib/index.d.ts +248 -0
  115. package/js/src/static_dependencies/starknet/types/lib/index.js +52 -0
  116. package/js/src/static_dependencies/starknet/types/typedData.d.ts +44 -0
  117. package/js/src/static_dependencies/starknet/types/typedData.js +19 -0
  118. package/js/src/static_dependencies/starknet/utils/address.d.ts +53 -0
  119. package/js/src/static_dependencies/starknet/utils/address.js +89 -0
  120. package/js/src/static_dependencies/starknet/utils/assert.d.ts +7 -0
  121. package/js/src/static_dependencies/starknet/utils/assert.js +17 -0
  122. package/js/src/static_dependencies/starknet/utils/cairoDataTypes/felt.d.ts +6 -0
  123. package/js/src/static_dependencies/starknet/utils/cairoDataTypes/felt.js +43 -0
  124. package/js/src/static_dependencies/starknet/utils/cairoDataTypes/uint256.d.ts +72 -0
  125. package/js/src/static_dependencies/starknet/utils/cairoDataTypes/uint256.js +117 -0
  126. package/js/src/static_dependencies/starknet/utils/cairoDataTypes/uint512.d.ts +76 -0
  127. package/js/src/static_dependencies/starknet/utils/cairoDataTypes/uint512.js +136 -0
  128. package/js/src/static_dependencies/starknet/utils/calldata/byteArray.d.ts +32 -0
  129. package/js/src/static_dependencies/starknet/utils/calldata/byteArray.js +59 -0
  130. package/js/src/static_dependencies/starknet/utils/calldata/cairo.d.ts +183 -0
  131. package/js/src/static_dependencies/starknet/utils/calldata/cairo.js +229 -0
  132. package/js/src/static_dependencies/starknet/utils/calldata/enum/CairoCustomEnum.d.ts +38 -0
  133. package/js/src/static_dependencies/starknet/utils/calldata/enum/CairoCustomEnum.js +57 -0
  134. package/js/src/static_dependencies/starknet/utils/calldata/enum/CairoOption.d.ts +35 -0
  135. package/js/src/static_dependencies/starknet/utils/calldata/enum/CairoOption.js +64 -0
  136. package/js/src/static_dependencies/starknet/utils/calldata/enum/CairoResult.d.ts +34 -0
  137. package/js/src/static_dependencies/starknet/utils/calldata/enum/CairoResult.js +63 -0
  138. package/js/src/static_dependencies/starknet/utils/calldata/enum/index.d.ts +3 -0
  139. package/js/src/static_dependencies/starknet/utils/calldata/enum/index.js +9 -0
  140. package/js/src/static_dependencies/starknet/utils/calldata/formatter.d.ts +9 -0
  141. package/js/src/static_dependencies/starknet/utils/calldata/formatter.js +67 -0
  142. package/js/src/static_dependencies/starknet/utils/calldata/index.d.ts +89 -0
  143. package/js/src/static_dependencies/starknet/utils/calldata/index.js +280 -0
  144. package/js/src/static_dependencies/starknet/utils/calldata/parser/index.d.ts +5 -0
  145. package/js/src/static_dependencies/starknet/utils/calldata/parser/index.js +30 -0
  146. package/js/src/static_dependencies/starknet/utils/calldata/parser/interface.d.ts +20 -0
  147. package/js/src/static_dependencies/starknet/utils/calldata/parser/interface.js +8 -0
  148. package/js/src/static_dependencies/starknet/utils/calldata/parser/parser-0-1.1.0.d.ts +24 -0
  149. package/js/src/static_dependencies/starknet/utils/calldata/parser/parser-0-1.1.0.js +36 -0
  150. package/js/src/static_dependencies/starknet/utils/calldata/parser/parser-2.0.0.d.ts +23 -0
  151. package/js/src/static_dependencies/starknet/utils/calldata/parser/parser-2.0.0.js +40 -0
  152. package/js/src/static_dependencies/starknet/utils/calldata/propertyOrder.d.ts +2 -0
  153. package/js/src/static_dependencies/starknet/utils/calldata/propertyOrder.js +155 -0
  154. package/js/src/static_dependencies/starknet/utils/calldata/requestParser.d.ts +11 -0
  155. package/js/src/static_dependencies/starknet/utils/calldata/requestParser.js +248 -0
  156. package/js/src/static_dependencies/starknet/utils/calldata/responseParser.d.ts +11 -0
  157. package/js/src/static_dependencies/starknet/utils/calldata/responseParser.js +214 -0
  158. package/js/src/static_dependencies/starknet/utils/calldata/tuple.d.ts +6 -0
  159. package/js/src/static_dependencies/starknet/utils/calldata/tuple.js +113 -0
  160. package/js/src/static_dependencies/starknet/utils/calldata/validate.d.ts +6 -0
  161. package/js/src/static_dependencies/starknet/utils/calldata/validate.js +208 -0
  162. package/js/src/static_dependencies/starknet/utils/encode.d.ts +207 -0
  163. package/js/src/static_dependencies/starknet/utils/encode.js +282 -0
  164. package/js/src/static_dependencies/starknet/utils/hash/classHash.d.ts +57 -0
  165. package/js/src/static_dependencies/starknet/utils/hash/classHash.js +224 -0
  166. package/js/src/static_dependencies/starknet/utils/hash/index.d.ts +6 -0
  167. package/js/src/static_dependencies/starknet/utils/hash/index.js +13 -0
  168. package/js/src/static_dependencies/starknet/utils/json.d.ts +24 -0
  169. package/js/src/static_dependencies/starknet/utils/json.js +43 -0
  170. package/js/src/static_dependencies/starknet/utils/merkle.d.ts +35 -0
  171. package/js/src/static_dependencies/starknet/utils/merkle.js +84 -0
  172. package/js/src/static_dependencies/starknet/utils/num.d.ts +182 -0
  173. package/js/src/static_dependencies/starknet/utils/num.js +244 -0
  174. package/js/src/static_dependencies/starknet/utils/selector.d.ts +48 -0
  175. package/js/src/static_dependencies/starknet/utils/selector.js +85 -0
  176. package/js/src/static_dependencies/starknet/utils/shortString.d.ts +57 -0
  177. package/js/src/static_dependencies/starknet/utils/shortString.js +96 -0
  178. package/js/src/static_dependencies/starknet/utils/starknetId.d.ts +113 -0
  179. package/js/src/static_dependencies/starknet/utils/starknetId.js +265 -0
  180. package/js/src/static_dependencies/starknet/utils/typedData.d.ts +54 -0
  181. package/js/src/static_dependencies/starknet/utils/typedData.js +321 -0
  182. package/js/src/static_dependencies/starknet/utils/uint256.d.ts +21 -0
  183. package/js/src/static_dependencies/starknet/utils/uint256.js +32 -0
  184. package/js/src/static_dependencies/starknet/utils/url.d.ts +29 -0
  185. package/js/src/static_dependencies/starknet/utils/url.js +70 -0
  186. package/js/src/woo.js +4 -2
  187. package/package.json +1 -1
@@ -0,0 +1,665 @@
1
+ 'use strict';
2
+
3
+ var blofin$1 = require('../blofin.js');
4
+ var errors = require('../base/errors.js');
5
+ var Cache = require('../base/ws/Cache.js');
6
+ var sha256 = require('../static_dependencies/noble-hashes/sha256.js');
7
+
8
+ // ---------------------------------------------------------------------------
9
+ // ---------------------------------------------------------------------------
10
+ class blofin extends blofin$1 {
11
+ describe() {
12
+ return this.deepExtend(super.describe(), {
13
+ 'has': {
14
+ 'ws': true,
15
+ 'watchTrades': true,
16
+ 'watchTradesForSymbols': true,
17
+ 'watchOrderBook': true,
18
+ 'watchOrderBookForSymbols': true,
19
+ 'watchTicker': true,
20
+ 'watchTickers': true,
21
+ 'watchOHLCV': true,
22
+ 'watchOHLCVForSymbols': true,
23
+ 'watchOrders': true,
24
+ 'watchOrdersForSymbols': true,
25
+ 'watchPositions': true,
26
+ },
27
+ 'urls': {
28
+ 'api': {
29
+ 'ws': {
30
+ 'swap': {
31
+ 'public': 'wss://openapi.blofin.com/ws/public',
32
+ 'private': 'wss://openapi.blofin.com/ws/private',
33
+ },
34
+ },
35
+ },
36
+ },
37
+ 'options': {
38
+ 'defaultType': 'swap',
39
+ 'tradesLimit': 1000,
40
+ // orderbook channel can be one from:
41
+ // - "books": 200 depth levels will be pushed in the initial full snapshot. Incremental data will be pushed every 100 ms for the changes in the order book during that period of time.
42
+ // - "books5": 5 depth levels snapshot will be pushed every time. Snapshot data will be pushed every 100 ms when there are changes in the 5 depth levels snapshot.
43
+ 'watchOrderBook': {
44
+ 'channel': 'books',
45
+ },
46
+ 'watchOrderBookForSymbols': {
47
+ 'channel': 'books',
48
+ },
49
+ },
50
+ 'streaming': {
51
+ 'ping': this.ping,
52
+ 'keepAlive': 25000, // 30 seconds max
53
+ },
54
+ });
55
+ }
56
+ ping(client) {
57
+ return 'ping';
58
+ }
59
+ handlePong(client, message) {
60
+ //
61
+ // 'pong'
62
+ //
63
+ client.lastPong = this.milliseconds();
64
+ }
65
+ async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
66
+ /**
67
+ * @method
68
+ * @name blofin#watchTrades
69
+ * @description get the list of most recent trades for a particular symbol
70
+ * @see https://docs.blofin.com/index.html#ws-trades-channel
71
+ * @param {string} symbol unified symbol of the market to fetch trades for
72
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
73
+ * @param {int} [limit] the maximum amount of trades to fetch
74
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
75
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
76
+ */
77
+ params['callerMethodName'] = 'watchTrades';
78
+ return await this.watchTradesForSymbols([symbol], since, limit, params);
79
+ }
80
+ async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
81
+ /**
82
+ * @method
83
+ * @name blofin#watchTradesForSymbols
84
+ * @description get the list of most recent trades for a list of symbols
85
+ * @see https://docs.blofin.com/index.html#ws-trades-channel
86
+ * @param {string[]} symbols unified symbol of the market to fetch trades for
87
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
88
+ * @param {int} [limit] the maximum amount of trades to fetch
89
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
90
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
91
+ */
92
+ await this.loadMarkets();
93
+ const trades = await this.watchMultipleWrapper(true, 'trades', 'watchTradesForSymbols', symbols, params);
94
+ if (this.newUpdates) {
95
+ const firstMarket = this.safeDict(trades, 0);
96
+ const firstSymbol = this.safeString(firstMarket, 'symbol');
97
+ limit = trades.getLimit(firstSymbol, limit);
98
+ }
99
+ return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
100
+ }
101
+ handleTrades(client, message) {
102
+ //
103
+ // {
104
+ // arg: {
105
+ // channel: "trades",
106
+ // instId: "DOGE-USDT",
107
+ // },
108
+ // data : [
109
+ // <same object as shown in REST example>,
110
+ // ...
111
+ // ]
112
+ // }
113
+ //
114
+ const arg = this.safeDict(message, 'arg');
115
+ const channelName = this.safeString(arg, 'channel');
116
+ const data = this.safeList(message, 'data');
117
+ if (data === undefined) {
118
+ return;
119
+ }
120
+ for (let i = 0; i < data.length; i++) {
121
+ const rawTrade = data[i];
122
+ const trade = this.parseWsTrade(rawTrade);
123
+ const symbol = trade['symbol'];
124
+ let stored = this.safeValue(this.trades, symbol);
125
+ if (stored === undefined) {
126
+ const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
127
+ stored = new Cache.ArrayCache(limit);
128
+ this.trades[symbol] = stored;
129
+ }
130
+ stored.append(trade);
131
+ const messageHash = channelName + ':' + symbol;
132
+ client.resolve(stored, messageHash);
133
+ }
134
+ }
135
+ parseWsTrade(trade, market = undefined) {
136
+ return this.parseTrade(trade, market);
137
+ }
138
+ async watchOrderBook(symbol, limit = undefined, params = {}) {
139
+ /**
140
+ * @method
141
+ * @name blofin#watchOrderBook
142
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
143
+ * @see https://docs.blofin.com/index.html#ws-order-book-channel
144
+ * @param {string} symbol unified symbol of the market to fetch the order book for
145
+ * @param {int} [limit] the maximum amount of order book entries to return
146
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
147
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
148
+ */
149
+ params['callerMethodName'] = 'watchOrderBook';
150
+ return await this.watchOrderBookForSymbols([symbol], limit, params);
151
+ }
152
+ async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
153
+ /**
154
+ * @method
155
+ * @name blofin#watchOrderBookForSymbols
156
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
157
+ * @see https://docs.blofin.com/index.html#ws-order-book-channel
158
+ * @param {string[]} symbols unified array of symbols
159
+ * @param {int} [limit] the maximum amount of order book entries to return
160
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
161
+ * @param {string} [params.depth] the type of order book to subscribe to, default is 'depth/increase100', also accepts 'depth5' or 'depth20' or depth50
162
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
163
+ */
164
+ await this.loadMarkets();
165
+ let callerMethodName = undefined;
166
+ [callerMethodName, params] = this.handleParamString(params, 'callerMethodName', 'watchOrderBookForSymbols');
167
+ let channelName = undefined;
168
+ [channelName, params] = this.handleOptionAndParams(params, callerMethodName, 'channel', 'books');
169
+ // due to some problem, temporarily disable other channels
170
+ if (channelName !== 'books') {
171
+ throw new errors.NotSupported(this.id + ' ' + callerMethodName + '() at this moment ' + channelName + ' is not supported, coming soon');
172
+ }
173
+ const orderbook = await this.watchMultipleWrapper(true, channelName, callerMethodName, symbols, params);
174
+ return orderbook.limit();
175
+ }
176
+ handleOrderBook(client, message) {
177
+ //
178
+ // {
179
+ // arg: {
180
+ // channel: "books",
181
+ // instId: "DOGE-USDT",
182
+ // },
183
+ // action: "snapshot", // can be 'snapshot' or 'update'
184
+ // data: {
185
+ // asks: [ [ 0.08096, 1 ], [ 0.08097, 123 ], ... ],
186
+ // bids: [ [ 0.08095, 4 ], [ 0.08094, 237 ], ... ],
187
+ // ts: "1707491587909",
188
+ // prevSeqId: "0", // in case of 'update' there will be some value, less then seqId
189
+ // seqId: "3374250786",
190
+ // },
191
+ // }
192
+ //
193
+ const arg = this.safeDict(message, 'arg');
194
+ const channelName = this.safeString(arg, 'channel');
195
+ const data = this.safeDict(message, 'data');
196
+ const marketId = this.safeString(arg, 'instId');
197
+ const market = this.safeMarket(marketId);
198
+ const symbol = market['symbol'];
199
+ const messageHash = channelName + ':' + symbol;
200
+ if (!(symbol in this.orderbooks)) {
201
+ this.orderbooks[symbol] = this.orderBook();
202
+ }
203
+ const orderbook = this.orderbooks[symbol];
204
+ const timestamp = this.safeInteger(data, 'ts');
205
+ const action = this.safeString(message, 'action');
206
+ if (action === 'snapshot') {
207
+ const orderBookSnapshot = this.parseOrderBook(data, symbol, timestamp);
208
+ orderBookSnapshot['nonce'] = this.safeInteger(data, 'seqId');
209
+ orderbook.reset(orderBookSnapshot);
210
+ }
211
+ else {
212
+ const asks = this.safeList(data, 'asks', []);
213
+ const bids = this.safeList(data, 'bids', []);
214
+ this.handleDeltasWithKeys(orderbook['asks'], asks);
215
+ this.handleDeltasWithKeys(orderbook['bids'], bids);
216
+ orderbook['timestamp'] = timestamp;
217
+ orderbook['datetime'] = this.iso8601(timestamp);
218
+ }
219
+ this.orderbooks[symbol] = orderbook;
220
+ client.resolve(orderbook, messageHash);
221
+ }
222
+ async watchTicker(symbol, params = {}) {
223
+ /**
224
+ * @method
225
+ * @name blofin#watchTicker
226
+ * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
227
+ * @see https://docs.blofin.com/index.html#ws-tickers-channel
228
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
229
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
230
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
231
+ */
232
+ params['callerMethodName'] = 'watchTicker';
233
+ const market = this.market(symbol);
234
+ symbol = market['symbol'];
235
+ const result = await this.watchTickers([symbol], params);
236
+ return result[symbol];
237
+ }
238
+ async watchTickers(symbols = undefined, params = {}) {
239
+ /**
240
+ * @method
241
+ * @name blofin#watchTickers
242
+ * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
243
+ * @see https://docs.blofin.com/index.html#ws-tickers-channel
244
+ * @param {string[]} symbols unified symbol of the market to fetch the ticker for
245
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
246
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
247
+ */
248
+ if (symbols === undefined) {
249
+ throw new errors.NotSupported(this.id + ' watchTickers() requires a list of symbols');
250
+ }
251
+ const ticker = await this.watchMultipleWrapper(true, 'tickers', 'watchTickers', symbols, params);
252
+ if (this.newUpdates) {
253
+ const tickers = {};
254
+ tickers[ticker['symbol']] = ticker;
255
+ return tickers;
256
+ }
257
+ return this.filterByArray(this.tickers, 'symbol', symbols);
258
+ }
259
+ handleTicker(client, message) {
260
+ //
261
+ // message
262
+ //
263
+ // {
264
+ // arg: {
265
+ // channel: "tickers",
266
+ // instId: "DOGE-USDT",
267
+ // },
268
+ // data: [
269
+ // <same object as shown in REST example>
270
+ // ],
271
+ // }
272
+ //
273
+ const arg = this.safeDict(message, 'arg');
274
+ const channelName = this.safeString(arg, 'channel');
275
+ const data = this.safeList(message, 'data');
276
+ for (let i = 0; i < data.length; i++) {
277
+ const ticker = this.parseWsTicker(data[i]);
278
+ const symbol = ticker['symbol'];
279
+ const messageHash = channelName + ':' + symbol;
280
+ this.tickers[symbol] = ticker;
281
+ client.resolve(this.tickers[symbol], messageHash);
282
+ }
283
+ }
284
+ parseWsTicker(ticker, market = undefined) {
285
+ return this.parseTicker(ticker, market);
286
+ }
287
+ async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
288
+ /**
289
+ * @method
290
+ * @name blofin#watchOHLCV
291
+ * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
292
+ * @param {string} symbol unified symbol of the market to fetch OHLCV data for
293
+ * @param {string} timeframe the length of time each candle represents
294
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
295
+ * @param {int} [limit] the maximum amount of candles to fetch
296
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
297
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
298
+ */
299
+ params['callerMethodName'] = 'watchOHLCV';
300
+ const result = await this.watchOHLCVForSymbols([[symbol, timeframe]], since, limit, params);
301
+ return result[symbol][timeframe];
302
+ }
303
+ async watchOHLCVForSymbols(symbolsAndTimeframes, since = undefined, limit = undefined, params = {}) {
304
+ /**
305
+ * @method
306
+ * @name blofin#watchOHLCVForSymbols
307
+ * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
308
+ * @see https://docs.blofin.com/index.html#ws-candlesticks-channel
309
+ * @param {string[][]} symbolsAndTimeframes array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
310
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
311
+ * @param {int} [limit] the maximum amount of candles to fetch
312
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
313
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
314
+ */
315
+ const symbolsLength = symbolsAndTimeframes.length;
316
+ if (symbolsLength === 0 || !Array.isArray(symbolsAndTimeframes[0])) {
317
+ throw new errors.ArgumentsRequired(this.id + " watchOHLCVForSymbols() requires a an array of symbols and timeframes, like [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]");
318
+ }
319
+ await this.loadMarkets();
320
+ const [symbol, timeframe, candles] = await this.watchMultipleWrapper(true, 'candle', 'watchOHLCVForSymbols', symbolsAndTimeframes, params);
321
+ if (this.newUpdates) {
322
+ limit = candles.getLimit(symbol, limit);
323
+ }
324
+ const filtered = this.filterBySinceLimit(candles, since, limit, 0, true);
325
+ return this.createOHLCVObject(symbol, timeframe, filtered);
326
+ }
327
+ handleOHLCV(client, message) {
328
+ //
329
+ // message
330
+ //
331
+ // {
332
+ // arg: {
333
+ // channel: "candle1m",
334
+ // instId: "DOGE-USDT",
335
+ // },
336
+ // data: [
337
+ // [ same object as shown in REST example ]
338
+ // ],
339
+ // }
340
+ //
341
+ const arg = this.safeDict(message, 'arg');
342
+ const channelName = this.safeString(arg, 'channel');
343
+ const data = this.safeList(message, 'data');
344
+ const marketId = this.safeString(arg, 'instId');
345
+ const market = this.safeMarket(marketId);
346
+ const symbol = market['symbol'];
347
+ const interval = channelName.replace('candle', '');
348
+ const unifiedTimeframe = this.findTimeframe(interval);
349
+ this.ohlcvs[symbol] = this.safeDict(this.ohlcvs, symbol, {});
350
+ let stored = this.safeValue(this.ohlcvs[symbol], unifiedTimeframe);
351
+ if (stored === undefined) {
352
+ const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
353
+ stored = new Cache.ArrayCacheByTimestamp(limit);
354
+ this.ohlcvs[symbol][unifiedTimeframe] = stored;
355
+ }
356
+ for (let i = 0; i < data.length; i++) {
357
+ const candle = data[i];
358
+ const parsed = this.parseOHLCV(candle, market);
359
+ stored.append(parsed);
360
+ }
361
+ const resolveData = [symbol, unifiedTimeframe, stored];
362
+ const messageHash = 'candle' + interval + ':' + symbol;
363
+ client.resolve(resolveData, messageHash);
364
+ }
365
+ async watchBalance(params = {}) {
366
+ /**
367
+ * @method
368
+ * @name blofin#watchBalance
369
+ * @description query for balance and get the amount of funds available for trading or funds locked in orders
370
+ * @see https://docs.blofin.com/index.html#ws-account-channel
371
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
372
+ * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
373
+ */
374
+ await this.loadMarkets();
375
+ await this.authenticate();
376
+ let marketType = undefined;
377
+ [marketType, params] = this.handleMarketTypeAndParams('watchBalance', undefined, params);
378
+ if (marketType === 'spot') {
379
+ throw new errors.NotSupported(this.id + ' watchBalance() is not supported for spot markets yet');
380
+ }
381
+ const messageHash = marketType + ':balance';
382
+ const sub = {
383
+ 'channel': 'account',
384
+ };
385
+ const request = this.getSubscriptionRequest([sub]);
386
+ const url = this.implodeHostname(this.urls['api']['ws'][marketType]['private']);
387
+ return await this.watch(url, messageHash, this.deepExtend(request, params), messageHash);
388
+ }
389
+ handleBalance(client, message) {
390
+ //
391
+ // {
392
+ // arg: {
393
+ // channel: "account",
394
+ // },
395
+ // data: <same object as shown in REST example>,
396
+ // }
397
+ //
398
+ const marketType = 'swap'; // for now
399
+ if (!(marketType in this.balance)) {
400
+ this.balance[marketType] = {};
401
+ }
402
+ this.balance[marketType] = this.parseWsBalance(message);
403
+ const messageHash = marketType + ':balance';
404
+ client.resolve(this.balance[marketType], messageHash);
405
+ }
406
+ parseWsBalance(message) {
407
+ return this.parseBalance(message);
408
+ }
409
+ async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
410
+ /**
411
+ * @method
412
+ * @name alpaca#watchOrders
413
+ * @description watches information on multiple orders made by the user
414
+ * @param {string} symbol unified market symbol of the market orders were made in
415
+ * @param {int} [since] the earliest time in ms to fetch orders for
416
+ * @param {int} [limit] the maximum number of order structures to retrieve
417
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
418
+ * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure
419
+ */
420
+ params['callerMethodName'] = 'watchOrders';
421
+ const symbolsArray = (symbol !== undefined) ? [symbol] : [];
422
+ return await this.watchOrdersForSymbols(symbolsArray, since, limit, params);
423
+ }
424
+ async watchOrdersForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
425
+ /**
426
+ * @method
427
+ * @name blofin#watchOrdersForSymbols
428
+ * @description watches information on multiple orders made by the user across multiple symbols
429
+ * @see https://docs.blofin.com/index.html#ws-order-channel
430
+ * @param {string} symbol unified market symbol of the market orders were made in
431
+ * @param {int} [since] the earliest time in ms to fetch orders for
432
+ * @param {int} [limit] the maximum number of order structures to retrieve
433
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
434
+ * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure
435
+ */
436
+ await this.authenticate();
437
+ await this.loadMarkets();
438
+ const orders = await this.watchMultipleWrapper(false, 'orders', 'watchOrdersForSymbols', symbols, params);
439
+ if (this.newUpdates) {
440
+ const first = this.safeValue(orders, 0);
441
+ const tradeSymbol = this.safeString(first, 'symbol');
442
+ limit = orders.getLimit(tradeSymbol, limit);
443
+ }
444
+ return this.filterBySinceLimit(orders, since, limit, 'timestamp', true);
445
+ }
446
+ handleOrders(client, message) {
447
+ //
448
+ // {
449
+ // action: 'update',
450
+ // arg: { channel: 'orders' },
451
+ // data: [
452
+ // <same object as shown in REST example>
453
+ // ]
454
+ // }
455
+ //
456
+ if (this.orders === undefined) {
457
+ const limit = this.safeInteger(this.options, 'ordersLimit', 1000);
458
+ this.orders = new Cache.ArrayCacheBySymbolById(limit);
459
+ }
460
+ const orders = this.orders;
461
+ const arg = this.safeDict(message, 'arg');
462
+ const channelName = this.safeString(arg, 'channel');
463
+ const data = this.safeList(message, 'data');
464
+ for (let i = 0; i < data.length; i++) {
465
+ const order = this.parseWsOrder(data[i]);
466
+ const symbol = order['symbol'];
467
+ const messageHash = channelName + ':' + symbol;
468
+ orders.append(order);
469
+ client.resolve(orders, messageHash);
470
+ client.resolve(orders, channelName);
471
+ }
472
+ }
473
+ parseWsOrder(order, market = undefined) {
474
+ return this.parseOrder(order, market);
475
+ }
476
+ async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
477
+ /**
478
+ * @method
479
+ * @name blofin#watchPositions
480
+ * @see https://docs.blofin.com/index.html#ws-positions-channel
481
+ * @description watch all open positions
482
+ * @param {string[]|undefined} symbols list of unified market symbols
483
+ * @param {object} params extra parameters specific to the exchange API endpoint
484
+ * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
485
+ */
486
+ await this.authenticate();
487
+ await this.loadMarkets();
488
+ const newPositions = await this.watchMultipleWrapper(false, 'positions', 'watchPositions', symbols, params);
489
+ if (this.newUpdates) {
490
+ return newPositions;
491
+ }
492
+ return this.filterBySymbolsSinceLimit(this.positions, symbols, since, limit);
493
+ }
494
+ handlePositions(client, message) {
495
+ //
496
+ // {
497
+ // arg: { channel: 'positions' },
498
+ // data: [
499
+ // <same object as shown in REST example>
500
+ // ]
501
+ // }
502
+ //
503
+ if (this.positions === undefined) {
504
+ this.positions = new Cache.ArrayCacheBySymbolBySide();
505
+ }
506
+ const cache = this.positions;
507
+ const arg = this.safeDict(message, 'arg');
508
+ const channelName = this.safeString(arg, 'channel');
509
+ const data = this.safeList(message, 'data');
510
+ for (let i = 0; i < data.length; i++) {
511
+ const position = this.parseWsPosition(data[i]);
512
+ cache.append(position);
513
+ const messageHash = channelName + ':' + position['symbol'];
514
+ client.resolve(position, messageHash);
515
+ }
516
+ }
517
+ parseWsPosition(position, market = undefined) {
518
+ return this.parsePosition(position, market);
519
+ }
520
+ async watchMultipleWrapper(isPublic, channelName, callerMethodName, symbolsArray = undefined, params = {}) {
521
+ // underlier method for all watch-multiple symbols
522
+ await this.loadMarkets();
523
+ [callerMethodName, params] = this.handleParamString(params, 'callerMethodName', callerMethodName);
524
+ // if OHLCV method are being called, then symbols would be symbolsAndTimeframes (multi-dimensional) array
525
+ const isOHLCV = (channelName === 'candle');
526
+ let symbols = isOHLCV ? this.getListFromObjectValues(symbolsArray, 0) : symbolsArray;
527
+ symbols = this.marketSymbols(symbols, undefined, true, true);
528
+ let firstMarket = undefined;
529
+ const firstSymbol = this.safeString(symbols, 0);
530
+ if (firstSymbol !== undefined) {
531
+ firstMarket = this.market(firstSymbol);
532
+ }
533
+ let marketType = undefined;
534
+ [marketType, params] = this.handleMarketTypeAndParams(callerMethodName, firstMarket, params);
535
+ if (marketType !== 'swap') {
536
+ throw new errors.NotSupported(this.id + ' ' + callerMethodName + '() does not support ' + marketType + ' markets yet');
537
+ }
538
+ let rawSubscriptions = [];
539
+ const messageHashes = [];
540
+ if (symbols === undefined) {
541
+ symbols = [];
542
+ }
543
+ const symbolsLength = symbols.length;
544
+ if (symbolsLength > 0) {
545
+ for (let i = 0; i < symbols.length; i++) {
546
+ const current = symbols[i];
547
+ let market = undefined;
548
+ let channel = channelName;
549
+ if (isOHLCV) {
550
+ market = this.market(current);
551
+ const tfArray = symbolsArray[i];
552
+ const tf = tfArray[1];
553
+ const interval = this.safeString(this.timeframes, tf, tf);
554
+ channel += interval;
555
+ }
556
+ else {
557
+ market = this.market(current);
558
+ }
559
+ const topic = {
560
+ 'channel': channel,
561
+ 'instId': market['id'],
562
+ };
563
+ rawSubscriptions.push(topic);
564
+ messageHashes.push(channel + ':' + market['symbol']);
565
+ }
566
+ }
567
+ else {
568
+ rawSubscriptions.push({ 'channel': channelName });
569
+ messageHashes.push(channelName);
570
+ }
571
+ // private channel are difference, they only need plural channel name for multiple symbols
572
+ if (this.inArray(channelName, ['orders', 'positions'])) {
573
+ rawSubscriptions = [{ 'channel': channelName }];
574
+ }
575
+ const request = this.getSubscriptionRequest(rawSubscriptions);
576
+ const privateOrPublic = isPublic ? 'public' : 'private';
577
+ const url = this.implodeHostname(this.urls['api']['ws'][marketType][privateOrPublic]);
578
+ return await this.watchMultiple(url, messageHashes, this.deepExtend(request, params), messageHashes);
579
+ }
580
+ getSubscriptionRequest(args) {
581
+ return {
582
+ 'op': 'subscribe',
583
+ 'args': args,
584
+ };
585
+ }
586
+ handleMessage(client, message) {
587
+ //
588
+ // message examples
589
+ //
590
+ // {
591
+ // arg: {
592
+ // channel: "trades",
593
+ // instId: "DOGE-USDT",
594
+ // },
595
+ // event: "subscribe"
596
+ // }
597
+ //
598
+ // incoming data updates' examples can be seen under each handler method
599
+ //
600
+ const methods = {
601
+ // public
602
+ 'pong': this.handlePong,
603
+ 'trades': this.handleTrades,
604
+ 'books': this.handleOrderBook,
605
+ 'tickers': this.handleTicker,
606
+ 'candle': this.handleOHLCV,
607
+ // private
608
+ 'account': this.handleBalance,
609
+ 'orders': this.handleOrders,
610
+ 'positions': this.handlePositions,
611
+ };
612
+ let method = undefined;
613
+ if (message === 'pong') {
614
+ method = this.safeValue(methods, 'pong');
615
+ }
616
+ else {
617
+ const event = this.safeString(message, 'event');
618
+ if (event === 'subscribe') {
619
+ return;
620
+ }
621
+ else if (event === 'login') {
622
+ client.resolve(message, 'authenticate_hash');
623
+ return;
624
+ }
625
+ else if (event === 'error') {
626
+ throw new errors.ExchangeError(this.id + ' error: ' + this.json(message));
627
+ }
628
+ const arg = this.safeDict(message, 'arg');
629
+ const channelName = this.safeString(arg, 'channel');
630
+ method = this.safeValue(methods, channelName);
631
+ if (!method && channelName.indexOf('candle') >= 0) {
632
+ method = methods['candle'];
633
+ }
634
+ }
635
+ if (method) {
636
+ method.call(this, client, message);
637
+ }
638
+ }
639
+ async authenticate(params = {}) {
640
+ this.checkRequiredCredentials();
641
+ const milliseconds = this.milliseconds();
642
+ const messageHash = 'authenticate_hash';
643
+ const timestamp = milliseconds.toString();
644
+ const nonce = 'n_' + timestamp;
645
+ const auth = '/users/self/verify' + 'GET' + timestamp + '' + nonce;
646
+ const signature = this.stringToBase64(this.hmac(this.encode(auth), this.encode(this.secret), sha256.sha256));
647
+ const request = {
648
+ 'op': 'login',
649
+ 'args': [
650
+ {
651
+ 'apiKey': this.apiKey,
652
+ 'passphrase': this.password,
653
+ 'timestamp': timestamp,
654
+ 'nonce': nonce,
655
+ 'sign': signature,
656
+ },
657
+ ],
658
+ };
659
+ const marketType = 'swap'; // for now
660
+ const url = this.implodeHostname(this.urls['api']['ws'][marketType]['private']);
661
+ await this.watch(url, messageHash, this.deepExtend(request, params), messageHash);
662
+ }
663
+ }
664
+
665
+ module.exports = blofin;