ccxt 4.5.55 → 4.5.57

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 (321) hide show
  1. package/README.md +215 -10
  2. package/dist/ccxt.browser.min.js +10 -10
  3. package/dist/cjs/ccxt.js +6 -11
  4. package/dist/cjs/src/aftermath.js +10 -5
  5. package/dist/cjs/src/alpaca.js +2 -2
  6. package/dist/cjs/src/apex.js +26 -17
  7. package/dist/cjs/src/arkham.js +10 -7
  8. package/dist/cjs/src/ascendex.js +8 -5
  9. package/dist/cjs/src/aster.js +7 -4
  10. package/dist/cjs/src/backpack.js +4 -4
  11. package/dist/cjs/src/base/Exchange.js +72 -35
  12. package/dist/cjs/src/base/functions/io.js +25 -0
  13. package/dist/cjs/src/base/functions.js +1 -0
  14. package/dist/cjs/src/bigone.js +10 -7
  15. package/dist/cjs/src/binance.js +196 -198
  16. package/dist/cjs/src/bingx.js +7 -7
  17. package/dist/cjs/src/bitfinex.js +71 -58
  18. package/dist/cjs/src/bitflyer.js +2 -1
  19. package/dist/cjs/src/bitget.js +16 -5
  20. package/dist/cjs/src/bitmart.js +18 -10
  21. package/dist/cjs/src/bitmex.js +8 -5
  22. package/dist/cjs/src/bitopro.js +2 -2
  23. package/dist/cjs/src/bitrue.js +4 -3
  24. package/dist/cjs/src/bitso.js +7 -4
  25. package/dist/cjs/src/bitstamp.js +7 -4
  26. package/dist/cjs/src/bitteam.js +1 -1
  27. package/dist/cjs/src/bittrade.js +2 -2
  28. package/dist/cjs/src/bitvavo.js +457 -34
  29. package/dist/cjs/src/blofin.js +28 -4
  30. package/dist/cjs/src/bullish.js +6 -5
  31. package/dist/cjs/src/bybit.js +19 -17
  32. package/dist/cjs/src/bybiteu.js +1 -0
  33. package/dist/cjs/src/bydfi.js +1 -1
  34. package/dist/cjs/src/cex.js +3 -3
  35. package/dist/cjs/src/coinbase.js +75 -65
  36. package/dist/cjs/src/coinbaseexchange.js +4 -3
  37. package/dist/cjs/src/coinbaseinternational.js +17 -10
  38. package/dist/cjs/src/coinex.js +79 -77
  39. package/dist/cjs/src/coinmetro.js +1 -1
  40. package/dist/cjs/src/coinsph.js +5 -5
  41. package/dist/cjs/src/cryptocom.js +52 -54
  42. package/dist/cjs/src/cryptomus.js +43 -39
  43. package/dist/cjs/src/deepcoin.js +9 -5
  44. package/dist/cjs/src/delta.js +53 -53
  45. package/dist/cjs/src/deribit.js +35 -35
  46. package/dist/cjs/src/derive.js +31 -31
  47. package/dist/cjs/src/digifinex.js +45 -45
  48. package/dist/cjs/src/exmo.js +104 -122
  49. package/dist/cjs/src/extended.js +3497 -0
  50. package/dist/cjs/src/foxbit.js +72 -76
  51. package/dist/cjs/src/gate.js +53 -53
  52. package/dist/cjs/src/gemini.js +45 -45
  53. package/dist/cjs/src/grvt.js +17 -11
  54. package/dist/cjs/src/hashkey.js +56 -58
  55. package/dist/cjs/src/hibachi.js +1 -1
  56. package/dist/cjs/src/hitbtc.js +5 -14
  57. package/dist/cjs/src/hollaex.js +51 -54
  58. package/dist/cjs/src/htx.js +84 -72
  59. package/dist/cjs/src/hyperliquid.js +60 -55
  60. package/dist/cjs/src/indodax.js +4 -3
  61. package/dist/cjs/src/kraken.js +71 -71
  62. package/dist/cjs/src/krakenfutures.js +2 -1
  63. package/dist/cjs/src/kucoin.js +3 -2
  64. package/dist/cjs/src/latoken.js +30 -32
  65. package/dist/cjs/src/lbank.js +64 -60
  66. package/dist/cjs/src/lighter.js +36 -38
  67. package/dist/cjs/src/luno.js +36 -44
  68. package/dist/cjs/src/mercado.js +2 -1
  69. package/dist/cjs/src/mexc.js +72 -63
  70. package/dist/cjs/src/modetrade.js +51 -53
  71. package/dist/cjs/src/ndax.js +35 -37
  72. package/dist/cjs/src/okx.js +23 -5
  73. package/dist/cjs/src/onetrading.js +21 -23
  74. package/dist/cjs/src/p2b.js +8 -4
  75. package/dist/cjs/src/paradex.js +3 -2
  76. package/dist/cjs/src/phemex.js +47 -47
  77. package/dist/cjs/src/poloniex.js +19 -13
  78. package/dist/cjs/src/pro/alpaca.js +1 -1
  79. package/dist/cjs/src/pro/apex.js +11 -2
  80. package/dist/cjs/src/pro/arkham.js +1 -1
  81. package/dist/cjs/src/pro/aster.js +10 -9
  82. package/dist/cjs/src/pro/backpack.js +1 -1
  83. package/dist/cjs/src/pro/binance.js +6 -6
  84. package/dist/cjs/src/pro/bingx.js +7 -2
  85. package/dist/cjs/src/pro/bitget.js +1 -1
  86. package/dist/cjs/src/pro/bithumb.js +1 -1
  87. package/dist/cjs/src/pro/bitmart.js +10 -0
  88. package/dist/cjs/src/pro/bitmex.js +1 -1
  89. package/dist/cjs/src/pro/bitstamp.js +1 -1
  90. package/dist/cjs/src/pro/blockchaincom.js +1 -1
  91. package/dist/cjs/src/pro/bybit.js +1 -1
  92. package/dist/cjs/src/pro/cex.js +1 -1
  93. package/dist/cjs/src/pro/coinex.js +1 -1
  94. package/dist/cjs/src/pro/coinone.js +1 -1
  95. package/dist/cjs/src/pro/cryptocom.js +3 -1
  96. package/dist/cjs/src/pro/dydx.js +1 -1
  97. package/dist/cjs/src/pro/exmo.js +1 -1
  98. package/dist/cjs/src/pro/extended.js +865 -0
  99. package/dist/cjs/src/pro/gate.js +1 -1
  100. package/dist/cjs/src/pro/grvt.js +8 -0
  101. package/dist/cjs/src/pro/htx.js +4 -4
  102. package/dist/cjs/src/pro/independentreserve.js +1 -1
  103. package/dist/cjs/src/pro/krakenfutures.js +16 -4
  104. package/dist/cjs/src/pro/kucoin.js +1 -1
  105. package/dist/cjs/src/pro/luno.js +3 -3
  106. package/dist/cjs/src/pro/modetrade.js +3 -3
  107. package/dist/cjs/src/pro/okx.js +4 -4
  108. package/dist/cjs/src/pro/onetrading.js +1 -1
  109. package/dist/cjs/src/pro/toobit.js +1 -1
  110. package/dist/cjs/src/pro/weex.js +1 -1
  111. package/dist/cjs/src/pro/woo.js +4 -4
  112. package/dist/cjs/src/pro/woofipro.js +3 -3
  113. package/dist/cjs/src/pro/xt.js +1 -1
  114. package/dist/cjs/src/static_dependencies/starknet/utils/hash/classHash.js +7 -7
  115. package/dist/cjs/src/tokocrypto.js +1 -1
  116. package/dist/cjs/src/toobit.js +3 -3
  117. package/dist/cjs/src/upbit.js +3 -3
  118. package/dist/cjs/src/weex.js +57 -62
  119. package/dist/cjs/src/whitebit.js +61 -63
  120. package/dist/cjs/src/woo.js +66 -55
  121. package/dist/cjs/src/woofipro.js +54 -48
  122. package/dist/cjs/src/xt.js +3 -2
  123. package/dist/cjs/src/yobit.js +4 -2
  124. package/dist/cjs/src/zebpay.js +73 -75
  125. package/js/ccxt.d.ts +8 -14
  126. package/js/ccxt.js +6 -10
  127. package/js/src/abstract/bitvavo.d.ts +15 -7
  128. package/js/src/abstract/extended.d.ts +58 -0
  129. package/js/src/abstract/mexc.d.ts +1 -0
  130. package/js/src/aftermath.js +10 -5
  131. package/js/src/alpaca.js +2 -2
  132. package/js/src/apex.d.ts +1 -1
  133. package/js/src/apex.js +26 -17
  134. package/js/src/arkham.js +10 -7
  135. package/js/src/ascendex.js +8 -5
  136. package/js/src/aster.js +7 -4
  137. package/js/src/backpack.js +4 -4
  138. package/js/src/base/Exchange.d.ts +10 -6
  139. package/js/src/base/Exchange.js +72 -35
  140. package/js/src/base/functions/io.d.ts +7 -0
  141. package/js/src/base/functions/io.js +24 -0
  142. package/js/src/bigone.js +10 -7
  143. package/js/src/binance.d.ts +2 -0
  144. package/js/src/binance.js +200 -202
  145. package/js/src/bingx.js +7 -7
  146. package/js/src/bitfinex.d.ts +2 -0
  147. package/js/src/bitfinex.js +71 -58
  148. package/js/src/bitflyer.js +2 -1
  149. package/js/src/bitget.js +16 -5
  150. package/js/src/bitmart.js +18 -10
  151. package/js/src/bitmex.js +8 -5
  152. package/js/src/bitopro.js +2 -2
  153. package/js/src/bitrue.js +4 -3
  154. package/js/src/bitso.js +7 -4
  155. package/js/src/bitstamp.js +7 -4
  156. package/js/src/bitteam.js +1 -1
  157. package/js/src/bittrade.js +2 -2
  158. package/js/src/bitvavo.d.ts +114 -21
  159. package/js/src/bitvavo.js +457 -34
  160. package/js/src/blofin.d.ts +1 -0
  161. package/js/src/blofin.js +28 -4
  162. package/js/src/bullish.js +6 -5
  163. package/js/src/bybit.d.ts +1 -1
  164. package/js/src/bybit.js +19 -17
  165. package/js/src/bybiteu.js +1 -0
  166. package/js/src/bydfi.js +1 -1
  167. package/js/src/cex.js +3 -3
  168. package/js/src/coinbase.d.ts +63 -56
  169. package/js/src/coinbase.js +75 -65
  170. package/js/src/coinbaseexchange.js +4 -3
  171. package/js/src/coinbaseinternational.d.ts +1 -1
  172. package/js/src/coinbaseinternational.js +17 -10
  173. package/js/src/coinex.d.ts +2 -1
  174. package/js/src/coinex.js +79 -77
  175. package/js/src/coinmetro.d.ts +1 -1
  176. package/js/src/coinmetro.js +1 -1
  177. package/js/src/coinsph.js +5 -5
  178. package/js/src/cryptocom.d.ts +1 -0
  179. package/js/src/cryptocom.js +52 -54
  180. package/js/src/cryptomus.d.ts +2 -1
  181. package/js/src/cryptomus.js +43 -39
  182. package/js/src/deepcoin.js +9 -5
  183. package/js/src/delta.d.ts +1 -0
  184. package/js/src/delta.js +53 -53
  185. package/js/src/deribit.d.ts +1 -0
  186. package/js/src/deribit.js +35 -35
  187. package/js/src/derive.d.ts +1 -0
  188. package/js/src/derive.js +31 -31
  189. package/js/src/digifinex.d.ts +1 -0
  190. package/js/src/digifinex.js +45 -45
  191. package/js/src/exmo.d.ts +1 -0
  192. package/js/src/exmo.js +104 -122
  193. package/js/src/extended.d.ts +554 -0
  194. package/js/src/extended.js +3490 -0
  195. package/js/src/foxbit.d.ts +1 -0
  196. package/js/src/foxbit.js +72 -76
  197. package/js/src/gate.d.ts +1 -0
  198. package/js/src/gate.js +53 -53
  199. package/js/src/gemini.d.ts +2 -1
  200. package/js/src/gemini.js +45 -45
  201. package/js/src/grvt.d.ts +1 -1
  202. package/js/src/grvt.js +17 -11
  203. package/js/src/hashkey.d.ts +1 -0
  204. package/js/src/hashkey.js +56 -58
  205. package/js/src/hibachi.d.ts +1 -1
  206. package/js/src/hibachi.js +1 -1
  207. package/js/src/hitbtc.d.ts +0 -1
  208. package/js/src/hitbtc.js +5 -14
  209. package/js/src/hollaex.d.ts +1 -0
  210. package/js/src/hollaex.js +51 -54
  211. package/js/src/htx.d.ts +1 -0
  212. package/js/src/htx.js +84 -72
  213. package/js/src/hyperliquid.d.ts +5 -4
  214. package/js/src/hyperliquid.js +60 -55
  215. package/js/src/indodax.js +4 -3
  216. package/js/src/kraken.d.ts +2 -1
  217. package/js/src/kraken.js +71 -71
  218. package/js/src/krakenfutures.js +2 -1
  219. package/js/src/kucoin.js +3 -2
  220. package/js/src/latoken.d.ts +1 -0
  221. package/js/src/latoken.js +30 -32
  222. package/js/src/lbank.d.ts +1 -0
  223. package/js/src/lbank.js +64 -60
  224. package/js/src/lighter.d.ts +2 -1
  225. package/js/src/lighter.js +36 -38
  226. package/js/src/luno.d.ts +1 -0
  227. package/js/src/luno.js +36 -44
  228. package/js/src/mercado.js +2 -1
  229. package/js/src/mexc.d.ts +4 -3
  230. package/js/src/mexc.js +72 -63
  231. package/js/src/modetrade.d.ts +1 -0
  232. package/js/src/modetrade.js +51 -53
  233. package/js/src/ndax.d.ts +1 -0
  234. package/js/src/ndax.js +35 -37
  235. package/js/src/okx.js +23 -5
  236. package/js/src/onetrading.d.ts +2 -1
  237. package/js/src/onetrading.js +21 -23
  238. package/js/src/p2b.js +8 -4
  239. package/js/src/paradex.js +3 -2
  240. package/js/src/phemex.d.ts +1 -0
  241. package/js/src/phemex.js +47 -47
  242. package/js/src/poloniex.js +19 -13
  243. package/js/src/pro/alpaca.js +1 -1
  244. package/js/src/pro/apex.js +11 -2
  245. package/js/src/pro/arkham.js +1 -1
  246. package/js/src/pro/aster.js +10 -9
  247. package/js/src/pro/backpack.js +1 -1
  248. package/js/src/pro/binance.d.ts +1 -1
  249. package/js/src/pro/binance.js +6 -6
  250. package/js/src/pro/bingx.js +7 -2
  251. package/js/src/pro/bitget.js +1 -1
  252. package/js/src/pro/bithumb.js +1 -1
  253. package/js/src/pro/bitmart.js +10 -0
  254. package/js/src/pro/bitmex.js +1 -1
  255. package/js/src/pro/bitstamp.js +1 -1
  256. package/js/src/pro/blockchaincom.js +1 -1
  257. package/js/src/pro/bybit.js +1 -1
  258. package/js/src/pro/cex.js +1 -1
  259. package/js/src/pro/coinex.js +1 -1
  260. package/js/src/pro/coinone.js +1 -1
  261. package/js/src/pro/cryptocom.js +3 -1
  262. package/js/src/pro/dydx.js +1 -1
  263. package/js/src/pro/exmo.js +1 -1
  264. package/js/src/pro/extended.d.ts +126 -0
  265. package/js/src/pro/extended.js +858 -0
  266. package/js/src/pro/gate.js +1 -1
  267. package/js/src/pro/grvt.js +8 -0
  268. package/js/src/pro/htx.d.ts +4 -4
  269. package/js/src/pro/htx.js +4 -4
  270. package/js/src/pro/independentreserve.js +1 -1
  271. package/js/src/pro/krakenfutures.d.ts +4 -4
  272. package/js/src/pro/krakenfutures.js +16 -4
  273. package/js/src/pro/kucoin.js +1 -1
  274. package/js/src/pro/luno.d.ts +1 -1
  275. package/js/src/pro/luno.js +3 -3
  276. package/js/src/pro/modetrade.d.ts +3 -3
  277. package/js/src/pro/modetrade.js +3 -3
  278. package/js/src/pro/okx.d.ts +4 -4
  279. package/js/src/pro/okx.js +4 -4
  280. package/js/src/pro/onetrading.js +1 -1
  281. package/js/src/pro/toobit.js +1 -1
  282. package/js/src/pro/weex.js +1 -1
  283. package/js/src/pro/woo.d.ts +4 -4
  284. package/js/src/pro/woo.js +4 -4
  285. package/js/src/pro/woofipro.d.ts +3 -3
  286. package/js/src/pro/woofipro.js +3 -3
  287. package/js/src/pro/xt.js +1 -1
  288. package/js/src/tokocrypto.js +1 -1
  289. package/js/src/toobit.d.ts +1 -1
  290. package/js/src/toobit.js +3 -3
  291. package/js/src/upbit.js +3 -3
  292. package/js/src/weex.d.ts +1 -0
  293. package/js/src/weex.js +57 -62
  294. package/js/src/whitebit.d.ts +1 -0
  295. package/js/src/whitebit.js +61 -63
  296. package/js/src/woo.d.ts +1 -0
  297. package/js/src/woo.js +66 -55
  298. package/js/src/woofipro.d.ts +1 -0
  299. package/js/src/woofipro.js +54 -48
  300. package/js/src/xt.js +3 -2
  301. package/js/src/yobit.js +4 -2
  302. package/js/src/zebpay.d.ts +2 -1
  303. package/js/src/zebpay.js +73 -75
  304. package/package.json +25 -11
  305. package/dist/cjs/src/gateio.js +0 -18
  306. package/dist/cjs/src/oxfun.js +0 -2931
  307. package/dist/cjs/src/pro/gateio.js +0 -18
  308. package/dist/cjs/src/pro/oxfun.js +0 -1113
  309. package/js/src/abstract/gateio.d.ts +0 -346
  310. package/js/src/abstract/gateio.js +0 -5
  311. package/js/src/abstract/oxfun.d.ts +0 -37
  312. package/js/src/gateio.d.ts +0 -4
  313. package/js/src/gateio.js +0 -11
  314. package/js/src/oxfun.d.ts +0 -442
  315. package/js/src/oxfun.js +0 -2924
  316. package/js/src/pro/gateio.d.ts +0 -4
  317. package/js/src/pro/gateio.js +0 -11
  318. package/js/src/pro/oxfun.d.ts +0 -234
  319. package/js/src/pro/oxfun.js +0 -1106
  320. /package/dist/cjs/src/abstract/{oxfun.js → extended.js} +0 -0
  321. /package/js/src/abstract/{oxfun.js → extended.js} +0 -0
@@ -0,0 +1,3497 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var extended$1 = require('./abstract/extended.js');
6
+ var Precise = require('./base/Precise.js');
7
+ var errors = require('./base/errors.js');
8
+ var number = require('./base/functions/number.js');
9
+
10
+ // ---------------------------------------------------------------------------
11
+ // ---------------------------------------------------------------------------
12
+ /**
13
+ * @class extended
14
+ * @augments Exchange
15
+ */
16
+ class extended extends extended$1["default"] {
17
+ describe() {
18
+ return this.deepExtend(super.describe(), {
19
+ 'id': 'extended',
20
+ 'name': 'Extended',
21
+ 'countries': ['SG'],
22
+ 'version': 'v2',
23
+ 'rateLimit': 600,
24
+ 'precisionMode': number.TICK_SIZE,
25
+ 'certified': false,
26
+ 'pro': true,
27
+ 'dex': true,
28
+ 'has': {
29
+ 'CORS': undefined,
30
+ 'spot': false,
31
+ 'margin': false,
32
+ 'swap': true,
33
+ 'future': false,
34
+ 'option': false,
35
+ 'addMargin': false,
36
+ 'borrowCrossMargin': false,
37
+ 'borrowIsolatedMargin': false,
38
+ 'cancelAllOrders': true,
39
+ 'cancelAllOrdersAfter': true,
40
+ 'cancelOrder': true,
41
+ 'cancelOrders': true,
42
+ 'closeAllPositions': false,
43
+ 'closePosition': false,
44
+ 'createConvertTrade': false,
45
+ 'createDepositAddress': false,
46
+ 'createMarketBuyOrderWithCost': false,
47
+ 'createMarketOrderWithCost': false,
48
+ 'createMarketSellOrderWithCost': false,
49
+ 'createOrder': true,
50
+ 'createOrders': false,
51
+ 'createOrderWithTakeProfitAndStopLoss': false,
52
+ 'createPostOnlyOrder': false,
53
+ 'createReduceOnlyOrder': false,
54
+ 'createStopLimitOrder': false,
55
+ 'createStopLossOrder': false,
56
+ 'createStopMarketOrder': false,
57
+ 'createStopOrder': false,
58
+ 'createTakeProfitOrder': false,
59
+ 'createTrailingAmountOrder': false,
60
+ 'createTrailingPercentOrder': false,
61
+ 'createTriggerOrder': false,
62
+ 'editOrder': true,
63
+ 'fetchAccounts': true,
64
+ 'fetchBalance': true,
65
+ 'fetchBorrowInterest': false,
66
+ 'fetchBorrowRateHistories': false,
67
+ 'fetchBorrowRateHistory': false,
68
+ 'fetchCanceledAndClosedOrders': false,
69
+ 'fetchCanceledOrders': true,
70
+ 'fetchClosedOrders': true,
71
+ 'fetchConvertCurrencies': false,
72
+ 'fetchConvertQuote': false,
73
+ 'fetchConvertTrade': false,
74
+ 'fetchConvertTradeHistory': false,
75
+ 'fetchCrossBorrowRate': false,
76
+ 'fetchCrossBorrowRates': false,
77
+ 'fetchCurrencies': true,
78
+ 'fetchDeposit': false,
79
+ 'fetchDepositAddress': false,
80
+ 'fetchDepositAddresses': false,
81
+ 'fetchDepositAddressesByNetwork': false,
82
+ 'fetchDeposits': true,
83
+ 'fetchDepositsWithdrawals': false,
84
+ 'fetchDepositWithdrawFee': false,
85
+ 'fetchDepositWithdrawFees': false,
86
+ 'fetchFundingHistory': true,
87
+ 'fetchFundingInterval': false,
88
+ 'fetchFundingIntervals': false,
89
+ 'fetchFundingRate': false,
90
+ 'fetchFundingRateHistory': true,
91
+ 'fetchFundingRates': false,
92
+ 'fetchIndexOHLCV': true,
93
+ 'fetchIsolatedBorrowRate': false,
94
+ 'fetchIsolatedBorrowRates': false,
95
+ 'fetchLedger': true,
96
+ 'fetchLeverage': true,
97
+ 'fetchLeverageTiers': false,
98
+ 'fetchLiquidations': false,
99
+ 'fetchLongShortRatio': false,
100
+ 'fetchLongShortRatioHistory': false,
101
+ 'fetchMarginAdjustmentHistory': false,
102
+ 'fetchMarginMode': false,
103
+ 'fetchMarketLeverageTiers': false,
104
+ 'fetchMarkets': true,
105
+ 'fetchMarkOHLCV': true,
106
+ 'fetchMarkPrice': false,
107
+ 'fetchMyLiquidations': false,
108
+ 'fetchMyTrades': true,
109
+ 'fetchOHLCV': true,
110
+ 'fetchOpenInterest': false,
111
+ 'fetchOpenInterestHistory': true,
112
+ 'fetchOpenOrders': true,
113
+ 'fetchOrder': true,
114
+ 'fetchOrderBook': true,
115
+ 'fetchOrderBooks': false,
116
+ 'fetchOrders': true,
117
+ 'fetchOrderTrades': false,
118
+ 'fetchPosition': true,
119
+ 'fetchPositionHistory': false,
120
+ 'fetchPositionMode': false,
121
+ 'fetchPositions': true,
122
+ 'fetchPositionsHistory': true,
123
+ 'fetchPositionsRisk': false,
124
+ 'fetchPremiumIndexOHLCV': false,
125
+ 'fetchStatus': false,
126
+ 'fetchTicker': true,
127
+ 'fetchTickers': true,
128
+ 'fetchTime': false,
129
+ 'fetchTrades': true,
130
+ 'fetchTradingFee': true,
131
+ 'fetchTradingFees': true,
132
+ 'fetchTransactions': true,
133
+ 'fetchTransfer': false,
134
+ 'fetchTransfers': true,
135
+ 'fetchWithdrawAddresses': false,
136
+ 'fetchWithdrawal': false,
137
+ 'fetchWithdrawals': true,
138
+ 'reduceMargin': false,
139
+ 'repayCrossMargin': false,
140
+ 'repayIsolatedMargin': false,
141
+ 'setLeverage': true,
142
+ 'setMargin': false,
143
+ 'setMarginMode': false,
144
+ 'setPositionMode': false,
145
+ 'signIn': false,
146
+ 'transfer': true,
147
+ 'withdraw': true,
148
+ },
149
+ 'features': {},
150
+ 'timeframes': {
151
+ '1m': 'PT1M',
152
+ '5m': 'PT5M',
153
+ '15m': 'PT15M',
154
+ '30m': 'PT30M',
155
+ '1h': 'PT1H',
156
+ '2h': 'PT2H',
157
+ '4h': 'PT4H',
158
+ '8h': 'PT8H',
159
+ '12h': 'PT12H',
160
+ '1d': 'PT24H',
161
+ '1w': 'P7D',
162
+ '1M': 'P30D',
163
+ },
164
+ 'hostname': 'extended.exchange',
165
+ 'urls': {
166
+ 'logo': 'https://github.com/user-attachments/assets/309d44db-2a50-4529-a27f-8f4492aec299',
167
+ 'api': {
168
+ 'rest': 'https://api.starknet.{hostname}',
169
+ },
170
+ 'test': {
171
+ 'rest': 'https://api.starknet.sepolia.{hostname}',
172
+ },
173
+ 'www': 'https://app.{hostname}',
174
+ 'doc': 'https://api.docs.{hostname}',
175
+ 'fees': 'https://docs.{hostname}/extended-resources/trading/trading-fees-and-rebates',
176
+ 'referral': '',
177
+ },
178
+ 'api': {
179
+ 'v1': {
180
+ 'public': {
181
+ 'get': [
182
+ 'info/markets',
183
+ 'info/assets',
184
+ 'info/assets/{asset}/price',
185
+ 'info/markets/{market}/stats',
186
+ 'info/markets/{market}/orderbook',
187
+ 'info/markets/{market}/trades',
188
+ 'info/candles/{market}/{candleType}',
189
+ 'info/{market}/funding',
190
+ 'info/{market}/open-interests',
191
+ 'info/builder/dashboard',
192
+ ],
193
+ },
194
+ 'private': {
195
+ 'get': [
196
+ 'user/accounts',
197
+ 'user/account/info',
198
+ 'user/balance',
199
+ 'user/spot/balances',
200
+ 'user/assetOperations',
201
+ 'user/positions',
202
+ 'user/positions/history',
203
+ 'user/orders',
204
+ 'user/orders/history',
205
+ 'user/orders/{id}',
206
+ 'user/orders/external/{externalId}',
207
+ 'user/trades',
208
+ 'user/funding/history',
209
+ 'user/rebates/stats',
210
+ 'user/leverage',
211
+ 'user/fees',
212
+ 'user/bridge/config',
213
+ 'user/bridge/quote',
214
+ 'user/affiliate',
215
+ 'user/referrals/status',
216
+ 'user/referrals/links',
217
+ 'user/referrals/dashboard',
218
+ 'user/rewards/earned',
219
+ 'user/rewards/leaderboard/stats',
220
+ 'portfolio/charts/equities',
221
+ 'portfolio/charts/pnl',
222
+ 'vault/public/performance',
223
+ 'vault/public/summary',
224
+ 'builder/trades',
225
+ ],
226
+ 'post': [
227
+ 'user/order',
228
+ 'user/order/massCancel',
229
+ 'user/deadmanswitch',
230
+ 'user/bridge/quote',
231
+ 'user/withdrawal',
232
+ 'user/transfer',
233
+ 'user/referrals/use',
234
+ 'user/referrals',
235
+ ],
236
+ 'put': [
237
+ 'user/referrals',
238
+ ],
239
+ 'patch': [
240
+ 'user/leverage',
241
+ ],
242
+ 'delete': [
243
+ 'user/order/{id}',
244
+ 'user/order',
245
+ ],
246
+ },
247
+ },
248
+ },
249
+ 'fees': {
250
+ 'taker': this.parseNumber('0.002'),
251
+ 'maker': this.parseNumber('0.002'),
252
+ },
253
+ 'requiredCredentials': {
254
+ 'apiKey': true,
255
+ 'secret': false,
256
+ 'privateKey': true,
257
+ },
258
+ 'exceptions': {
259
+ 'exact': {
260
+ '1000': errors.InvalidOrder,
261
+ '1001': errors.InvalidOrder,
262
+ '1002': errors.InvalidOrder,
263
+ '1003': errors.InvalidOrder,
264
+ '1004': errors.InvalidOrder,
265
+ '1005': errors.InvalidOrder,
266
+ '1006': errors.ExchangeError,
267
+ '1008': errors.InvalidOrder,
268
+ '1009': errors.InvalidOrder,
269
+ '1010': errors.ExchangeError,
270
+ '1011': errors.InvalidOrder,
271
+ '1012': errors.InvalidOrder,
272
+ '1013': errors.InvalidOrder,
273
+ '1014': errors.InvalidOrder,
274
+ '1049': errors.InvalidOrder,
275
+ '1050': errors.InvalidOrder,
276
+ '10501': errors.InvalidOrder,
277
+ '1052': errors.InvalidOrder,
278
+ '1053': errors.InvalidOrder,
279
+ '1100': errors.InvalidOrder,
280
+ '1101': errors.InvalidOrder,
281
+ '1102': errors.InvalidOrder,
282
+ '1120': errors.InvalidOrder,
283
+ '1121': errors.InvalidOrder,
284
+ '1122': errors.InvalidOrder,
285
+ '1123': errors.InvalidOrder,
286
+ '1124': errors.InvalidOrder,
287
+ '1125': errors.InvalidOrder,
288
+ '1126': errors.InvalidOrder,
289
+ '1127': errors.InvalidOrder,
290
+ '1128': errors.InvalidOrder,
291
+ '1129': errors.InvalidOrder,
292
+ '1130': errors.InvalidOrder,
293
+ '1131': errors.InvalidOrder,
294
+ '1132': errors.InvalidOrder,
295
+ '1133': errors.InvalidOrder,
296
+ '1134': errors.InvalidOrder,
297
+ '1135': errors.InvalidOrder,
298
+ '1136': errors.InvalidOrder,
299
+ '1137': errors.InvalidOrder,
300
+ '1138': errors.InvalidOrder,
301
+ '1139': errors.InvalidOrder,
302
+ '1140': errors.InsufficientFunds,
303
+ '1141': errors.InvalidOrder,
304
+ '1142': errors.InvalidOrder,
305
+ '1143': errors.InvalidOrder,
306
+ '1144': errors.InvalidOrder,
307
+ '1145': errors.InvalidOrder,
308
+ '1146': errors.InvalidOrder,
309
+ '1147': errors.InvalidOrder,
310
+ '1148': errors.InvalidOrder,
311
+ '1500': errors.InvalidOrder,
312
+ '1600': errors.BadRequest,
313
+ '1601': errors.BadRequest,
314
+ '1602': errors.BadRequest,
315
+ '1604': errors.BadRequest,
316
+ '1605': errors.BadRequest,
317
+ '1607': errors.BadRequest,
318
+ '1608': errors.BadRequest,
319
+ '1650': errors.BadRequest,
320
+ '1700': errors.BadRequest,
321
+ '1701': errors.BadRequest,
322
+ '1703': errors.BadRequest,
323
+ '1704': errors.BadRequest, // Referral code already applied.
324
+ },
325
+ 'broad': {},
326
+ },
327
+ 'options': {
328
+ 'builderFee': true,
329
+ 'builderFeeRate': '0.0001',
330
+ 'builderId': '257624',
331
+ },
332
+ });
333
+ }
334
+ async loadMarkets(reload = false, params = {}) {
335
+ const markets = await super.loadMarkets(reload, params);
336
+ const currenciesByNumericId = this.safeDict(this.options, 'currenciesByNumericId');
337
+ if ((currenciesByNumericId === undefined) || reload) {
338
+ this.options['currenciesByNumericId'] = this.indexByStringifiedNumericId(this.currencies);
339
+ }
340
+ return markets;
341
+ }
342
+ indexByStringifiedNumericId(input) {
343
+ const result = {};
344
+ if (input === undefined) {
345
+ return undefined;
346
+ }
347
+ const keys = Object.keys(input);
348
+ for (let i = 0; i < keys.length; i++) {
349
+ const key = keys[i];
350
+ const item = input[key];
351
+ const numericIdString = this.safeString(item, 'numericId');
352
+ if (numericIdString === undefined) {
353
+ continue;
354
+ }
355
+ result[numericIdString] = item;
356
+ }
357
+ return result;
358
+ }
359
+ /**
360
+ * @method
361
+ * @name extended#fetchMarkets
362
+ * @description retrieves data on all markets for extended
363
+ * @see https://api.docs.extended.exchange/#get-markets
364
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
365
+ * @returns {object[]} an array of objects representing market data
366
+ */
367
+ async fetchMarkets(params = {}) {
368
+ const response = await this.v1PublicGetInfoMarkets(params);
369
+ //
370
+ // {
371
+ // "status": "OK",
372
+ // "data": [
373
+ // {
374
+ // "name": "BTC-USD",
375
+ // "uiName": "BTC-USD",
376
+ // "category": "Crypto",
377
+ // "subCategory": "L1",
378
+ // "assetName": "BTC",
379
+ // "assetPrecision": 5,
380
+ // "collateralAssetName": "USD",
381
+ // "collateralAssetPrecision": 6,
382
+ // "description": "Bitcoin",
383
+ // "active": true,
384
+ // "status": "ACTIVE",
385
+ // "marketStats": {
386
+ // "dailyVolume": "231016077.512960",
387
+ // "dailyVolumeBase": "3025.00058",
388
+ // "dailyPriceChange": "420",
389
+ // "dailyPriceChangePercentage": "0.0055",
390
+ // "dailyLow": "75635",
391
+ // "dailyHigh": "77399",
392
+ // "lastPrice": "77259",
393
+ // "askPrice": "77260",
394
+ // "bidPrice": "77259",
395
+ // "markPrice": "77259.680250000004",
396
+ // "indexPrice": "77299.020412500001",
397
+ // "fundingRate": "0.000013",
398
+ // "nextFundingRate": 1777442400000,
399
+ // "openInterest": "115861923.311902",
400
+ // "openInterestBase": "1500.40958",
401
+ // "deleverageLevels": {
402
+ // "shortPositions": [
403
+ // {
404
+ // "level": 1,
405
+ // "rankingLowerBound": "-815.7788"
406
+ // },
407
+ // {
408
+ // "level": 2,
409
+ // "rankingLowerBound": "-2.1328"
410
+ // },
411
+ // {
412
+ // "level": 3,
413
+ // "rankingLowerBound": "-0.9297"
414
+ // },
415
+ // {
416
+ // "level": 4,
417
+ // "rankingLowerBound": "0.0000"
418
+ // }
419
+ // ],
420
+ // "longPositions": [
421
+ // {
422
+ // "level": 1,
423
+ // "rankingLowerBound": "-47234.9095"
424
+ // },
425
+ // {
426
+ // "level": 2,
427
+ // "rankingLowerBound": "-0.0030"
428
+ // },
429
+ // {
430
+ // "level": 3,
431
+ // "rankingLowerBound": "0.0020"
432
+ // },
433
+ // {
434
+ // "level": 4,
435
+ // "rankingLowerBound": "0.0033"
436
+ // }
437
+ // ]
438
+ // }
439
+ // },
440
+ // "tradingConfig": {
441
+ // "minOrderSize": "0.0001",
442
+ // "minOrderSizeChange": "0.00001",
443
+ // "minPriceChange": "1",
444
+ // "maxMarketOrderValue": "3000000",
445
+ // "maxLimitOrderValue": "15000000",
446
+ // "maxPositionValue": "60000000",
447
+ // "maxLeverage": "50.00",
448
+ // "hourlyFundingRateCap": "0.25",
449
+ // "maxNumOrders": "200",
450
+ // "limitPriceCap": "0.05",
451
+ // "limitPriceFloor": "0.05",
452
+ // "riskFactorConfig": [
453
+ // {
454
+ // "upperBound": "4000000",
455
+ // "riskFactor": "0.02",
456
+ // "isAvailableForUsers": true
457
+ // }
458
+ // ]
459
+ // },
460
+ // "l2Config": {
461
+ // "type": "STARKX",
462
+ // "collateralId": "0x1",
463
+ // "syntheticId": "0x4254432d3600000000000000000000",
464
+ // "syntheticResolution": 1000000,
465
+ // "collateralResolution": 1000000
466
+ // },
467
+ // "visibleOnUi": true,
468
+ // "createdAt": 1752829532673
469
+ // }
470
+ // ]
471
+ // }
472
+ //
473
+ const data = this.safeList(response, 'data', []);
474
+ return this.parseMarkets(data);
475
+ }
476
+ parseMarket(market) {
477
+ //
478
+ // {
479
+ // "name": "BTC-USD",
480
+ // "uiName": "BTC-USD",
481
+ // "category": "Crypto",
482
+ // "subCategory": "L1",
483
+ // "assetName": "BTC",
484
+ // "assetPrecision": 5,
485
+ // "collateralAssetName": "USD",
486
+ // "collateralAssetPrecision": 6,
487
+ // "description": "Bitcoin",
488
+ // "active": true,
489
+ // "status": "ACTIVE",
490
+ // "marketStats": { ... },
491
+ // "tradingConfig": {
492
+ // "minOrderSize": "0.0001",
493
+ // "minOrderSizeChange": "0.00001",
494
+ // "minPriceChange": "1",
495
+ // "maxMarketOrderValue": "3000000",
496
+ // "maxLimitOrderValue": "15000000",
497
+ // "maxPositionValue": "60000000",
498
+ // "maxLeverage": "50.00",
499
+ // "hourlyFundingRateCap": "0.25",
500
+ // "maxNumOrders": "200",
501
+ // "limitPriceCap": "0.05",
502
+ // "limitPriceFloor": "0.05",
503
+ // "riskFactorConfig": [
504
+ // {
505
+ // "upperBound": "4000000",
506
+ // "riskFactor": "0.02",
507
+ // "isAvailableForUsers": true
508
+ // }
509
+ // ]
510
+ // },
511
+ // "l2Config": { ... },
512
+ // "visibleOnUi": true,
513
+ // "createdAt": 1752829532673
514
+ // }
515
+ //
516
+ const tradingConfig = this.safeDict(market, 'tradingConfig', {});
517
+ const marketId = this.safeString(market, 'name');
518
+ let baseId = this.safeString(market, 'assetName');
519
+ if (baseId.indexOf('SPOT') >= 0) {
520
+ baseId = baseId.replace('SPOT', '');
521
+ }
522
+ const quoteId = this.safeString(market, 'collateralAssetName');
523
+ const base = this.safeCurrencyCode(baseId);
524
+ let quote = this.safeCurrencyCode(quoteId);
525
+ if (quoteId === 'USD') {
526
+ quote = 'USDC';
527
+ }
528
+ const status = this.safeString(market, 'status');
529
+ const active = (status === 'ACTIVE');
530
+ const amountPrecision = this.safeNumber(tradingConfig, 'minOrderSizeChange');
531
+ const pricePrecision = this.safeNumber(tradingConfig, 'minPriceChange');
532
+ const maxLeverage = this.safeNumber(tradingConfig, 'maxLeverage');
533
+ const minAmount = this.safeNumber(tradingConfig, 'minOrderSize');
534
+ const maxCost = this.safeNumber(tradingConfig, 'maxLimitOrderValue');
535
+ const created = this.safeInteger(market, 'createdAt');
536
+ let settleId = undefined;
537
+ let settle = undefined;
538
+ let symbol = base + '/' + quote;
539
+ let isSpot = false;
540
+ let type = this.safeStringLower(market, 'type');
541
+ let contractSize = undefined;
542
+ let linear = undefined;
543
+ let inverse = undefined;
544
+ if (type === 'spot') {
545
+ isSpot = true;
546
+ }
547
+ else {
548
+ type = 'swap';
549
+ settleId = quoteId;
550
+ settle = quote;
551
+ symbol += ':' + settle;
552
+ contractSize = this.parseNumber('1');
553
+ linear = true;
554
+ inverse = false;
555
+ }
556
+ return this.safeMarketStructure({
557
+ 'id': marketId,
558
+ 'symbol': symbol,
559
+ 'base': base,
560
+ 'quote': quote,
561
+ 'settle': settle,
562
+ 'baseId': baseId,
563
+ 'quoteId': quoteId,
564
+ 'settleId': settleId,
565
+ 'type': type,
566
+ 'spot': isSpot,
567
+ 'margin': false,
568
+ 'swap': !isSpot,
569
+ 'future': false,
570
+ 'option': false,
571
+ 'active': active,
572
+ 'contract': !isSpot,
573
+ 'linear': linear,
574
+ 'inverse': inverse,
575
+ 'taker': this.safeNumber(this.fees, 'taker'),
576
+ 'maker': this.safeNumber(this.fees, 'maker'),
577
+ 'contractSize': contractSize,
578
+ 'expiry': undefined,
579
+ 'expiryDatetime': undefined,
580
+ 'strike': undefined,
581
+ 'optionType': undefined,
582
+ 'precision': {
583
+ 'amount': amountPrecision,
584
+ 'price': pricePrecision,
585
+ },
586
+ 'limits': {
587
+ 'leverage': {
588
+ 'min': this.parseNumber('1'),
589
+ 'max': maxLeverage,
590
+ },
591
+ 'amount': {
592
+ 'min': minAmount,
593
+ 'max': undefined,
594
+ },
595
+ 'price': {
596
+ 'min': undefined,
597
+ 'max': undefined,
598
+ },
599
+ 'cost': {
600
+ 'min': undefined,
601
+ 'max': maxCost,
602
+ },
603
+ },
604
+ 'created': created,
605
+ 'info': market,
606
+ });
607
+ }
608
+ /**
609
+ * @method
610
+ * @name extended#fetchCurrencies
611
+ * @description fetches all available currencies on an exchange
612
+ * @see https://api.docs.extended.exchange/#get-assets
613
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
614
+ * @returns {object} an associative dictionary of currencies
615
+ */
616
+ async fetchCurrencies(params = {}) {
617
+ const response = await this.v1PublicGetInfoAssets(params);
618
+ //
619
+ // {
620
+ // "status": "OK",
621
+ // "data": [
622
+ // {
623
+ // "id": 1,
624
+ // "name": "USD",
625
+ // "symbol": "USD",
626
+ // "description": "USD Collateral",
627
+ // "precision": 6,
628
+ // "isActive": true,
629
+ // "isCollateral": true,
630
+ // "starkexId": "0x1",
631
+ // "starkexResolution": 1000000,
632
+ // "l1Id": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
633
+ // "l1Resolution": 1000000,
634
+ // "version": 3,
635
+ // "createdAt": 1752829532673,
636
+ // "type": "SPOT",
637
+ // "canBeUsedAsCollateral": true,
638
+ // "riskFactors": [],
639
+ // "availableForTradeFactors": []
640
+ // }
641
+ // ]
642
+ // }
643
+ //
644
+ const data = this.safeList(response, 'data', []);
645
+ return this.parseCurrencies(data);
646
+ }
647
+ parseCurrency(currency) {
648
+ //
649
+ // {
650
+ // "id": 1,
651
+ // "name": "USD",
652
+ // "symbol": "USD",
653
+ // "description": "USD Collateral",
654
+ // "precision": 6,
655
+ // "isActive": true,
656
+ // "isCollateral": true,
657
+ // "starkexId": "0x1",
658
+ // "starkexResolution": 1000000,
659
+ // "l1Id": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
660
+ // "l1Resolution": 1000000,
661
+ // "version": 3,
662
+ // "createdAt": 1752829532673,
663
+ // "type": "SPOT",
664
+ // "canBeUsedAsCollateral": true,
665
+ // "riskFactors": [],
666
+ // "availableForTradeFactors": []
667
+ // }
668
+ //
669
+ let currencyId = this.safeString(currency, 'symbol');
670
+ if ((currencyId !== undefined) && (currencyId.indexOf('SPOT') >= 0)) {
671
+ currencyId = currencyId.replace('SPOT', '');
672
+ }
673
+ let code = this.safeCurrencyCode(currencyId);
674
+ if (currencyId === 'USD') {
675
+ code = 'USDC';
676
+ }
677
+ const name = this.safeString(currency, 'name');
678
+ const precision = this.safeInteger(currency, 'precision');
679
+ const isActive = this.safeBool(currency, 'isActive');
680
+ return this.safeCurrencyStructure({
681
+ 'id': currencyId,
682
+ 'code': code,
683
+ 'numericId': this.safeInteger(currency, 'id'),
684
+ 'name': name,
685
+ 'active': isActive,
686
+ 'deposit': true,
687
+ 'withdraw': true,
688
+ 'precision': Math.pow(10, precision * -1),
689
+ 'type': 'other',
690
+ 'margin': this.safeBool(currency, 'canBeUsedAsCollateral'),
691
+ 'info': currency,
692
+ });
693
+ }
694
+ /**
695
+ * @method
696
+ * @name extended#fetchTicker
697
+ * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
698
+ * @see https://api.docs.extended.exchange/#get-market-statistics
699
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
700
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
701
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
702
+ */
703
+ async fetchTicker(symbol, params = {}) {
704
+ await this.loadMarkets();
705
+ const market = this.market(symbol);
706
+ const request = {
707
+ 'market': market['id'],
708
+ };
709
+ const response = await this.v1PublicGetInfoMarketsMarketStats(this.extend(request, params));
710
+ //
711
+ // {
712
+ // "status": "OK",
713
+ // "data": {
714
+ // "dailyVolume": "231216165.666600",
715
+ // "dailyVolumeBase": "3027.36710",
716
+ // "dailyPriceChange": "181",
717
+ // "dailyPriceChangePercentage": "0.0024",
718
+ // "dailyLow": "75635",
719
+ // "dailyHigh": "77399",
720
+ // "lastPrice": "77026",
721
+ // "askPrice": "77026",
722
+ // "bidPrice": "77025",
723
+ // "markPrice": "77006.091897999984",
724
+ // "indexPrice": "77050.739529925005",
725
+ // "fundingRate": "0.000012",
726
+ // "nextFundingRate": 1777446000000,
727
+ // "openInterest": "114851569.088316",
728
+ // "openInterestBase": "1491.33012",
729
+ // "deleverageLevels": {
730
+ // "shortPositions": [
731
+ // { "level": 1, "rankingLowerBound": "-784.2884" },
732
+ // { "level": 2, "rankingLowerBound": "-2.1078" },
733
+ // { "level": 3, "rankingLowerBound": "-0.8754" },
734
+ // { "level": 4, "rankingLowerBound": "0.0000" }
735
+ // ],
736
+ // "longPositions": [
737
+ // { "level": 1, "rankingLowerBound": "-47747.2010" },
738
+ // { "level": 2, "rankingLowerBound": "-0.0131" },
739
+ // { "level": 3, "rankingLowerBound": "0.0019" },
740
+ // { "level": 4, "rankingLowerBound": "0.0032" }
741
+ // ]
742
+ // }
743
+ // }
744
+ // }
745
+ //
746
+ const data = this.safeDict(response, 'data', {});
747
+ return this.parseTicker(data, market);
748
+ }
749
+ /**
750
+ * @method
751
+ * @name extended#fetchTickers
752
+ * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for all markets
753
+ * @see https://api.docs.extended.exchange/#get-markets
754
+ * @param {string[]} [symbols] unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
755
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
756
+ * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
757
+ */
758
+ async fetchTickers(symbols = undefined, params = {}) {
759
+ await this.loadMarkets();
760
+ symbols = this.marketSymbols(symbols);
761
+ const request = {};
762
+ if (symbols !== undefined) {
763
+ const marketIds = [];
764
+ for (let i = 0; i < symbols.length; i++) {
765
+ const market = this.market(symbols[i]);
766
+ marketIds.push(market['id']);
767
+ }
768
+ request['market'] = marketIds;
769
+ }
770
+ const response = await this.v1PublicGetInfoMarkets(this.extend(request, params));
771
+ //
772
+ // {
773
+ // "status": "OK",
774
+ // "data": [
775
+ // {
776
+ // "name": "BTC-USD",
777
+ // "assetName": "BTC",
778
+ // "collateralAssetName": "USD",
779
+ // "marketStats": {
780
+ // "dailyVolume": "231016077.512960",
781
+ // ...
782
+ // },
783
+ // ...
784
+ // }
785
+ // ]
786
+ // }
787
+ //
788
+ const data = this.safeList(response, 'data', []);
789
+ const tickers = {};
790
+ for (let i = 0; i < data.length; i++) {
791
+ const marketData = data[i];
792
+ const marketId = this.safeString(marketData, 'name');
793
+ const market = this.safeMarket(marketId);
794
+ const stats = this.safeDict(marketData, 'marketStats', {});
795
+ const ticker = this.parseTicker(stats, market);
796
+ const symbol = ticker['symbol'];
797
+ tickers[symbol] = ticker;
798
+ }
799
+ return this.filterByArrayTickers(tickers, 'symbol', symbols);
800
+ }
801
+ parseTicker(ticker, market = undefined) {
802
+ //
803
+ // {
804
+ // "dailyVolume": "231216165.666600",
805
+ // "dailyVolumeBase": "3027.36710",
806
+ // "dailyPriceChange": "181",
807
+ // "dailyPriceChangePercentage": "0.0024",
808
+ // "dailyLow": "75635",
809
+ // "dailyHigh": "77399",
810
+ // "lastPrice": "77026",
811
+ // "askPrice": "77026",
812
+ // "bidPrice": "77025",
813
+ // "markPrice": "77006.091897999984",
814
+ // "indexPrice": "77050.739529925005",
815
+ // "fundingRate": "0.000012",
816
+ // "nextFundingRate": 1777446000000,
817
+ // "openInterest": "114851569.088316",
818
+ // "openInterestBase": "1491.33012",
819
+ // "deleverageLevels": {
820
+ // "shortPositions": [
821
+ // { "level": 1, "rankingLowerBound": "-784.2884" },
822
+ // { "level": 2, "rankingLowerBound": "-2.1078" },
823
+ // { "level": 3, "rankingLowerBound": "-0.8754" },
824
+ // { "level": 4, "rankingLowerBound": "0.0000" }
825
+ // ],
826
+ // "longPositions": [
827
+ // { "level": 1, "rankingLowerBound": "-47747.2010" },
828
+ // { "level": 2, "rankingLowerBound": "-0.0131" },
829
+ // { "level": 3, "rankingLowerBound": "0.0019" },
830
+ // { "level": 4, "rankingLowerBound": "0.0032" }
831
+ // ]
832
+ // }
833
+ // }
834
+ //
835
+ const symbol = this.safeSymbol(undefined, market);
836
+ const last = this.safeNumber(ticker, 'lastPrice');
837
+ const percentageRaw = this.safeString(ticker, 'dailyPriceChangePercentage');
838
+ const percentage = (percentageRaw !== undefined) ? Precise["default"].stringMul(percentageRaw, '100') : undefined;
839
+ return this.safeTicker({
840
+ 'symbol': symbol,
841
+ 'timestamp': undefined,
842
+ 'datetime': undefined,
843
+ 'high': this.safeNumber(ticker, 'dailyHigh'),
844
+ 'low': this.safeNumber(ticker, 'dailyLow'),
845
+ 'bid': this.safeNumber(ticker, 'bidPrice'),
846
+ 'bidVolume': undefined,
847
+ 'ask': this.safeNumber(ticker, 'askPrice'),
848
+ 'askVolume': undefined,
849
+ 'vwap': undefined,
850
+ 'open': undefined,
851
+ 'close': last,
852
+ 'last': last,
853
+ 'previousClose': undefined,
854
+ 'change': this.safeNumber(ticker, 'dailyPriceChange'),
855
+ 'percentage': percentage,
856
+ 'average': undefined,
857
+ 'baseVolume': this.safeNumber(ticker, 'dailyVolumeBase'),
858
+ 'quoteVolume': this.safeNumber(ticker, 'dailyVolume'),
859
+ 'markPrice': this.safeNumber(ticker, 'markPrice'),
860
+ 'indexPrice': this.safeNumber(ticker, 'indexPrice'),
861
+ 'info': ticker,
862
+ }, market);
863
+ }
864
+ /**
865
+ * @method
866
+ * @name extended#fetchOrderBook
867
+ * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
868
+ * @see https://api.docs.extended.exchange/#get-market-order-book
869
+ * @param {string} symbol unified symbol of the market to fetch the order book for
870
+ * @param {int} [limit] the maximum amount of order book entries to return
871
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
872
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
873
+ */
874
+ async fetchOrderBook(symbol, limit = undefined, params = {}) {
875
+ await this.loadMarkets();
876
+ const market = this.market(symbol);
877
+ const request = {
878
+ 'market': market['id'],
879
+ };
880
+ const response = await this.v1PublicGetInfoMarketsMarketOrderbook(this.extend(request, params));
881
+ //
882
+ // {
883
+ // "status": "OK",
884
+ // "data": {
885
+ // "market": "BTC-USD",
886
+ // "bid": [
887
+ // {
888
+ // "qty": "14.46084",
889
+ // "price": "76214"
890
+ // }
891
+ // ],
892
+ // "ask": [
893
+ // {
894
+ // "qty": "0.11585",
895
+ // "price": "76215"
896
+ // }
897
+ // ]
898
+ // }
899
+ // }
900
+ //
901
+ const data = this.safeDict(response, 'data', {});
902
+ const timestamp = this.milliseconds();
903
+ const orderbook = this.parseOrderBook(data, market['symbol'], timestamp, 'bid', 'ask', 'price', 'qty');
904
+ if (limit !== undefined) {
905
+ orderbook['bids'] = this.arraySlice(orderbook['bids'], 0, limit);
906
+ orderbook['asks'] = this.arraySlice(orderbook['asks'], 0, limit);
907
+ }
908
+ return orderbook;
909
+ }
910
+ /**
911
+ * @method
912
+ * @name extended#fetchTrades
913
+ * @description get the list of most recent trades for a particular symbol
914
+ * @see https://api.docs.extended.exchange/#get-market-last-trades
915
+ * @param {string} symbol unified symbol of the market to fetch trades for
916
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
917
+ * @param {int} [limit] the maximum amount of trades to fetch
918
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
919
+ * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
920
+ */
921
+ async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
922
+ await this.loadMarkets();
923
+ const market = this.market(symbol);
924
+ const request = {
925
+ 'market': market['id'],
926
+ };
927
+ const response = await this.v1PublicGetInfoMarketsMarketTrades(this.extend(request, params));
928
+ //
929
+ // {
930
+ // "status": "OK",
931
+ // "data": [
932
+ // {
933
+ // "i": 2.049676905958871e+18,
934
+ // "m": "BTC-USD",
935
+ // "S": "SELL",
936
+ // "tT": "TRADE",
937
+ // "T": 1777516030193,
938
+ // "p": "76140",
939
+ // "q": "0.00165"
940
+ // }
941
+ // ]
942
+ // }
943
+ //
944
+ const data = this.safeList(response, 'data', []);
945
+ return this.parseTrades(data, market, since, limit);
946
+ }
947
+ /**
948
+ * @method
949
+ * @name extended#fetchMyTrades
950
+ * @description fetch all trades made by the user
951
+ * @see https://api.docs.extended.exchange/#get-trades
952
+ * @param {string} [symbol] unified market symbol of the trades
953
+ * @param {int} [since] the earliest time in ms to fetch trades for
954
+ * @param {int} [limit] the maximum number of trade structures to retrieve
955
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
956
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
957
+ * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
958
+ */
959
+ async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
960
+ await this.loadMarkets();
961
+ let paginate = false;
962
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchMyTrades', 'paginate');
963
+ if (paginate) {
964
+ return await this.fetchPaginatedCallCursor('fetchMyTrades', symbol, since, limit, params, 'cursor', 'cursor', undefined, 100);
965
+ }
966
+ let market = undefined;
967
+ const request = {};
968
+ if (symbol !== undefined) {
969
+ market = this.market(symbol);
970
+ request['market'] = market['id'];
971
+ }
972
+ if (limit !== undefined) {
973
+ request['limit'] = limit;
974
+ }
975
+ const response = await this.v1PrivateGetUserTrades(this.extend(params, request));
976
+ //
977
+ // {
978
+ // "status": "OK",
979
+ // "data": [
980
+ // {
981
+ // "id": 1,
982
+ // "orderId": 1784980437895231232,
983
+ // "externalId": "ExtId-1",
984
+ // "accountId": 1,
985
+ // "market": "BTC-USD",
986
+ // "side": "BUY",
987
+ // "price": "39000",
988
+ // "qty": "0.2",
989
+ // "value": "7800",
990
+ // "fee": "1.3",
991
+ // "tradeType": "TRADE",
992
+ // "isTaker": true,
993
+ // "createdTime": 1701563440000
994
+ // }
995
+ // ],
996
+ // "pagination": {
997
+ // "cursor": 1784963886257016832,
998
+ // "count": 1
999
+ // }
1000
+ // }
1001
+ //
1002
+ const data = this.safeList(response, 'data', []);
1003
+ const pagination = this.safeDict(response, 'pagination', {});
1004
+ const cursor = this.safeString(pagination, 'cursor');
1005
+ const result = [];
1006
+ const dataLength = data.length;
1007
+ for (let i = 0; i < dataLength; i++) {
1008
+ let entry = data[i];
1009
+ if ((cursor !== undefined) && (i === dataLength - 1)) {
1010
+ entry = this.extend(entry, { 'cursor': cursor });
1011
+ }
1012
+ result.push(entry);
1013
+ }
1014
+ return this.parseTrades(result, market, since, limit);
1015
+ }
1016
+ /**
1017
+ * @method
1018
+ * @name extended#fetchFundingHistory
1019
+ * @description fetch the funding payments history
1020
+ * @see https://api.docs.extended.exchange/#get-funding-payments
1021
+ * @param {string} [symbol] unified market symbol
1022
+ * @param {int} [since] the earliest time in ms to fetch funding history for
1023
+ * @param {int} [limit] the maximum number of funding history structures to retrieve
1024
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1025
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1026
+ * @returns {FundingHistory[]} a list of [funding history structures]{@link https://docs.ccxt.com/#/?id=funding-history-structure}
1027
+ */
1028
+ async fetchFundingHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
1029
+ await this.loadMarkets();
1030
+ let paginate = false;
1031
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchFundingHistory', 'paginate');
1032
+ if (paginate) {
1033
+ return await this.fetchPaginatedCallCursor('fetchFundingHistory', symbol, since, limit, params, 'cursor', 'cursor', undefined, 100);
1034
+ }
1035
+ let market = undefined;
1036
+ const request = {};
1037
+ if (symbol !== undefined) {
1038
+ market = this.market(symbol);
1039
+ request['market'] = market['id'];
1040
+ }
1041
+ if (since !== undefined) {
1042
+ request['startTime'] = since;
1043
+ }
1044
+ if (limit !== undefined) {
1045
+ request['limit'] = limit;
1046
+ }
1047
+ const response = await this.v1PrivateGetUserFundingHistory(this.extend(params, request));
1048
+ //
1049
+ // {
1050
+ // "status": "OK",
1051
+ // "data": [
1052
+ // {
1053
+ // "id": 8341,
1054
+ // "accountId": 3137,
1055
+ // "market": "BNB-USD",
1056
+ // "positionId": 1821237954501148672,
1057
+ // "side": "LONG",
1058
+ // "size": "1.116",
1059
+ // "value": "560.77401888",
1060
+ // "markPrice": "502.48568",
1061
+ // "fundingFee": "0",
1062
+ // "fundingRate": "0",
1063
+ // "paidTime": 1723147241346
1064
+ // }
1065
+ // ],
1066
+ // "pagination": {
1067
+ // "cursor": 8341,
1068
+ // "count": 1
1069
+ // }
1070
+ // }
1071
+ //
1072
+ const data = this.safeList(response, 'data', []);
1073
+ const pagination = this.safeDict(response, 'pagination', {});
1074
+ const cursor = this.safeString(pagination, 'cursor');
1075
+ const result = [];
1076
+ const dataLength = data.length;
1077
+ for (let i = 0; i < dataLength; i++) {
1078
+ let entry = data[i];
1079
+ if ((cursor !== undefined) && (i === dataLength - 1)) {
1080
+ entry = this.extend(entry, { 'cursor': cursor });
1081
+ }
1082
+ result.push(entry);
1083
+ }
1084
+ return this.parseFundingHistories(result, market, since, limit);
1085
+ }
1086
+ parseFundingHistory(history, market = undefined) {
1087
+ //
1088
+ // {
1089
+ // "id": 8341,
1090
+ // "accountId": 3137,
1091
+ // "market": "BNB-USD",
1092
+ // "positionId": 1821237954501148672,
1093
+ // "side": "LONG",
1094
+ // "size": "1.116",
1095
+ // "value": "560.77401888",
1096
+ // "markPrice": "502.48568",
1097
+ // "fundingFee": "0",
1098
+ // "fundingRate": "0",
1099
+ // "paidTime": 1723147241346
1100
+ // }
1101
+ //
1102
+ const marketId = this.safeString(history, 'market');
1103
+ market = this.safeMarket(marketId, market);
1104
+ const timestamp = this.safeInteger(history, 'paidTime');
1105
+ return {
1106
+ 'info': history,
1107
+ 'symbol': market['symbol'],
1108
+ 'code': market['settle'],
1109
+ 'timestamp': timestamp,
1110
+ 'datetime': this.iso8601(timestamp),
1111
+ 'id': this.safeString(history, 'id'),
1112
+ 'amount': this.safeNumber(history, 'fundingFee'),
1113
+ 'rate': this.safeNumber(history, 'fundingRate'),
1114
+ };
1115
+ }
1116
+ parseFundingHistories(histories, market = undefined, since = undefined, limit = undefined) {
1117
+ const result = [];
1118
+ for (let i = 0; i < histories.length; i++) {
1119
+ result.push(this.parseFundingHistory(histories[i], market));
1120
+ }
1121
+ const symbol = (market === undefined) ? undefined : market['symbol'];
1122
+ return this.filterBySymbolSinceLimit(result, symbol, since, limit);
1123
+ }
1124
+ parseTrade(trade, market = undefined) {
1125
+ //
1126
+ // fetchTrades
1127
+ //
1128
+ // {
1129
+ // "i": 2.049676905958871e+18,
1130
+ // "m": "BTC-USD",
1131
+ // "S": "SELL",
1132
+ // "tT": "TRADE",
1133
+ // "T": 1777516030193,
1134
+ // "p": "76140",
1135
+ // "q": "0.00165"
1136
+ // }
1137
+ //
1138
+ // fetchMyTrades
1139
+ //
1140
+ // {
1141
+ // "id": 1,
1142
+ // "orderId": 1784980437895231232,
1143
+ // "externalId": "ExtId-1",
1144
+ // "accountId": 1,
1145
+ // "market": "BTC-USD",
1146
+ // "side": "BUY",
1147
+ // "price": "39000",
1148
+ // "qty": "0.2",
1149
+ // "value": "7800",
1150
+ // "fee": "1.3",
1151
+ // "tradeType": "TRADE",
1152
+ // "isTaker": true,
1153
+ // "createdTime": 1701563440000
1154
+ // }
1155
+ //
1156
+ const marketId = this.safeString2(trade, 'm', 'market');
1157
+ market = this.safeMarket(marketId, market);
1158
+ const timestamp = this.safeInteger2(trade, 'T', 'createdTime');
1159
+ const priceString = this.safeString2(trade, 'p', 'price');
1160
+ const amountString = this.safeString2(trade, 'q', 'qty');
1161
+ const sideRaw = this.safeString2(trade, 'S', 'side');
1162
+ const side = (sideRaw !== undefined) ? sideRaw.toLowerCase() : undefined;
1163
+ const feeCost = this.safeString(trade, 'fee');
1164
+ const fee = (feeCost === undefined) ? undefined : {
1165
+ 'cost': feeCost,
1166
+ 'currency': (market === undefined) ? undefined : market['settle'],
1167
+ };
1168
+ const isTaker = this.safeBool(trade, 'isTaker');
1169
+ let takerOrMaker = undefined;
1170
+ if (isTaker !== undefined) {
1171
+ takerOrMaker = isTaker ? 'taker' : 'maker';
1172
+ }
1173
+ return this.safeTrade({
1174
+ 'id': this.safeString2(trade, 'i', 'id'),
1175
+ 'info': trade,
1176
+ 'timestamp': timestamp,
1177
+ 'datetime': this.iso8601(timestamp),
1178
+ 'symbol': market['symbol'],
1179
+ 'order': this.safeString(trade, 'orderId'),
1180
+ 'type': undefined,
1181
+ 'side': side,
1182
+ 'takerOrMaker': takerOrMaker,
1183
+ 'price': priceString,
1184
+ 'amount': amountString,
1185
+ 'cost': this.safeString(trade, 'value'),
1186
+ 'fee': fee,
1187
+ }, market);
1188
+ }
1189
+ /**
1190
+ * @method
1191
+ * @name extended#fetchOHLCV
1192
+ * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1193
+ * @see https://api.docs.extended.exchange/#get-candles-history
1194
+ * @param {string} symbol unified symbol of the market to fetch OHLCV data for
1195
+ * @param {string} timeframe the length of time each candle represents
1196
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
1197
+ * @param {int} [limit] the maximum amount of candles to fetch, default 100
1198
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1199
+ * @param {string} [params.candleType] candle type: 'trades' (default), 'mark-prices', or 'index-prices'
1200
+ * @param {string} [params.price] *ignored if params.candleType is set* 'mark' or 'index' for mark price and index price candles
1201
+ * @param {int} [params.until] end timestamp in ms for the requested period
1202
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
1203
+ */
1204
+ async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
1205
+ await this.loadMarkets();
1206
+ const market = this.market(symbol);
1207
+ const price = this.safeString(params, 'price');
1208
+ let candleType = this.safeString(params, 'candleType');
1209
+ if (candleType === undefined) {
1210
+ if (price === 'mark') {
1211
+ candleType = 'mark-prices';
1212
+ }
1213
+ else if (price === 'index') {
1214
+ candleType = 'index-prices';
1215
+ }
1216
+ else {
1217
+ candleType = 'trades';
1218
+ }
1219
+ }
1220
+ const until = this.safeInteger(params, 'until');
1221
+ params = this.omit(params, ['candleType', 'price', 'until']);
1222
+ const request = {
1223
+ 'market': market['id'],
1224
+ 'candleType': candleType,
1225
+ 'interval': this.safeString(this.timeframes, timeframe, timeframe),
1226
+ 'limit': (limit !== undefined) ? limit : 100,
1227
+ };
1228
+ if (until !== undefined) {
1229
+ request['endTime'] = until;
1230
+ }
1231
+ const response = await this.v1PublicGetInfoCandlesMarketCandleType(this.extend(request, params));
1232
+ //
1233
+ // {
1234
+ // "status": "OK",
1235
+ // "data": [
1236
+ // {
1237
+ // "o": "75657.5",
1238
+ // "l": "75657.5",
1239
+ // "h": "75657.5",
1240
+ // "c": "75657.5",
1241
+ // "v": "0",
1242
+ // "T": 1777517880000
1243
+ // }
1244
+ // ]
1245
+ // }
1246
+ //
1247
+ const data = this.safeList(response, 'data', []);
1248
+ return this.parseOHLCVs(data, market, timeframe, since, limit);
1249
+ }
1250
+ parseOHLCV(ohlcv, market = undefined) {
1251
+ //
1252
+ // {
1253
+ // "o": "75657.5",
1254
+ // "l": "75657.5",
1255
+ // "h": "75657.5",
1256
+ // "c": "75657.5",
1257
+ // "v": "0",
1258
+ // "T": 1777517880000
1259
+ // }
1260
+ //
1261
+ return [
1262
+ this.safeInteger(ohlcv, 'T'),
1263
+ this.safeNumber(ohlcv, 'o'),
1264
+ this.safeNumber(ohlcv, 'h'),
1265
+ this.safeNumber(ohlcv, 'l'),
1266
+ this.safeNumber(ohlcv, 'c'),
1267
+ this.safeNumber(ohlcv, 'v'),
1268
+ ];
1269
+ }
1270
+ /**
1271
+ * @method
1272
+ * @name extended#fetchFundingRateHistory
1273
+ * @description fetches historical funding rate prices
1274
+ * @see https://api.docs.extended.exchange/#get-funding-rates-history
1275
+ * @param {string} symbol unified symbol of the market to fetch funding rate history for
1276
+ * @param {int} [since] timestamp in ms of the earliest funding rate to fetch
1277
+ * @param {int} [limit] the maximum amount of entries to fetch
1278
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1279
+ * @param {int} [params.until] timestamp in ms of the latest funding rate to fetch
1280
+ * @param {int} [params.endTime] exchange-specific end timestamp in ms of the latest funding rate to fetch
1281
+ * @param {int} [params.cursor] offset of the result set
1282
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1283
+ * @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure}
1284
+ */
1285
+ async fetchFundingRateHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
1286
+ if (symbol === undefined) {
1287
+ throw new errors.ArgumentsRequired(this.id + ' fetchFundingRateHistory() requires a symbol argument');
1288
+ }
1289
+ await this.loadMarkets();
1290
+ let paginate = false;
1291
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchFundingRateHistory', 'paginate');
1292
+ if (paginate) {
1293
+ return await this.fetchPaginatedCallCursor('fetchFundingRateHistory', symbol, since, limit, params, 'cursor', 'cursor', undefined, 10000);
1294
+ }
1295
+ const market = this.market(symbol);
1296
+ symbol = market['symbol'];
1297
+ if (limit === undefined) {
1298
+ limit = 100;
1299
+ }
1300
+ const until = this.safeInteger(params, 'until', this.milliseconds());
1301
+ const endTime = this.safeInteger(params, 'endTime', until);
1302
+ params = this.omit(params, ['endTime', 'until']);
1303
+ if (since === undefined) {
1304
+ since = endTime - (limit * 60 * 60 * 1000);
1305
+ }
1306
+ const request = {
1307
+ 'market': market['id'],
1308
+ 'startTime': since,
1309
+ 'endTime': endTime,
1310
+ 'limit': limit,
1311
+ };
1312
+ const response = await this.v1PublicGetInfoMarketFunding(this.extend(request, params));
1313
+ //
1314
+ // {
1315
+ // "status": "OK",
1316
+ // "data": [
1317
+ // {
1318
+ // "m": "BTC-USD",
1319
+ // "f": "0.000008",
1320
+ // "T": 1777507201028
1321
+ // }
1322
+ // ],
1323
+ // "pagination": {
1324
+ // "cursor": 1784963886257016832,
1325
+ // "count": 1
1326
+ // }
1327
+ // }
1328
+ //
1329
+ const data = this.safeList(response, 'data', []);
1330
+ const pagination = this.safeDict(response, 'pagination', {});
1331
+ const cursor = this.safeString(pagination, 'cursor');
1332
+ const result = [];
1333
+ const dataLength = data.length;
1334
+ for (let i = 0; i < dataLength; i++) {
1335
+ let entry = data[i];
1336
+ if ((cursor !== undefined) && (i === dataLength - 1)) {
1337
+ entry = this.extend(entry, { 'cursor': cursor });
1338
+ }
1339
+ result.push(this.parseFundingRateHistory(entry, market));
1340
+ }
1341
+ const sorted = this.sortBy(result, 'timestamp');
1342
+ return this.filterBySymbolSinceLimit(sorted, symbol, since, limit);
1343
+ }
1344
+ parseFundingRateHistory(info, market = undefined) {
1345
+ //
1346
+ // {
1347
+ // "m": "BTC-USD",
1348
+ // "f": "0.000008",
1349
+ // "T": 1777507201028
1350
+ // }
1351
+ //
1352
+ const marketId = this.safeString(info, 'm');
1353
+ market = this.safeMarket(marketId, market);
1354
+ const timestamp = this.safeInteger(info, 'T');
1355
+ return {
1356
+ 'info': info,
1357
+ 'symbol': market['symbol'],
1358
+ 'fundingRate': this.safeNumber(info, 'f'),
1359
+ 'timestamp': timestamp,
1360
+ 'datetime': this.iso8601(timestamp),
1361
+ };
1362
+ }
1363
+ /**
1364
+ * @method
1365
+ * @name extended#fetchOpenInterestHistory
1366
+ * @description Retrieves the open interest history of a currency
1367
+ * @see https://api.docs.extended.exchange/#get-open-interest-history
1368
+ * @param {string} symbol unified CCXT market symbol
1369
+ * @param {string} timeframe '1h' or '1d'
1370
+ * @param {int} [since] the time(ms) of the earliest record to retrieve as a unix timestamp
1371
+ * @param {int} [limit] the maximum amount of open interest structures to retrieve
1372
+ * @param {object} [params] exchange specific parameters
1373
+ * @param {int} [params.until] timestamp in ms of the latest open interest record to fetch
1374
+ * @returns {object[]} an array of [open interest structures]{@link https://docs.ccxt.com/#/?id=open-interest-structure}
1375
+ */
1376
+ async fetchOpenInterestHistory(symbol, timeframe = '1h', since = undefined, limit = undefined, params = {}) {
1377
+ await this.loadMarkets();
1378
+ const market = this.market(symbol);
1379
+ const interval = this.safeString(this.timeframes, timeframe);
1380
+ if (!this.inArray(interval, ['PT1H', 'P1D'])) {
1381
+ throw new errors.BadRequest(this.id + ' fetchOpenInterestHistory() supports 1h and 1d timeframes only');
1382
+ }
1383
+ if (limit === undefined) {
1384
+ limit = 100;
1385
+ }
1386
+ const until = this.safeInteger(params, 'until', this.milliseconds());
1387
+ const endTime = this.safeInteger(params, 'endTime', until);
1388
+ params = this.omit(params, ['endTime', 'until']);
1389
+ if (since === undefined) {
1390
+ since = endTime - (limit * this.parseTimeframe(timeframe) * 1000);
1391
+ }
1392
+ const request = {
1393
+ 'market': market['id'],
1394
+ 'interval': interval,
1395
+ 'startTime': since,
1396
+ 'endTime': endTime,
1397
+ 'limit': limit,
1398
+ };
1399
+ const response = await this.v1PublicGetInfoMarketOpenInterests(this.extend(request, params));
1400
+ //
1401
+ // {
1402
+ // "status": "OK",
1403
+ // "data": [
1404
+ // {
1405
+ // "i": "112620590.6060360000000000",
1406
+ // "I": "1473.1408400000000000",
1407
+ // "t": 1777420800000
1408
+ // }
1409
+ // ]
1410
+ // }
1411
+ //
1412
+ const data = this.safeList(response, 'data', []);
1413
+ return this.parseOpenInterestsHistory(data, market, since, limit);
1414
+ }
1415
+ parseOpenInterest(interest, market = undefined) {
1416
+ //
1417
+ // {
1418
+ // "i": "112620590.6060360000000000",
1419
+ // "I": "1473.1408400000000000",
1420
+ // "t": 1777420800000
1421
+ // }
1422
+ //
1423
+ const timestamp = this.safeInteger(interest, 't');
1424
+ return this.safeOpenInterest({
1425
+ 'symbol': market['symbol'],
1426
+ 'openInterestAmount': this.safeNumber(interest, 'I'),
1427
+ 'openInterestValue': this.safeNumber(interest, 'i'),
1428
+ 'baseVolume': this.safeNumber(interest, 'I'),
1429
+ 'quoteVolume': this.safeNumber(interest, 'i'),
1430
+ 'timestamp': timestamp,
1431
+ 'datetime': this.iso8601(timestamp),
1432
+ 'info': interest,
1433
+ }, market);
1434
+ }
1435
+ /**
1436
+ * @method
1437
+ * @name extended#fetchBalance
1438
+ * @description query for balance and get the amount of funds available for trading or funds locked in orders
1439
+ * @see https://api.docs.extended.exchange/#get-spot-balances
1440
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1441
+ * @returns {object} a [balance structure]{@link https://docs.ccxt.com/?id=balance-structure}
1442
+ */
1443
+ async fetchBalance(params = {}) {
1444
+ await this.loadMarkets();
1445
+ const response = await this.v1PrivateGetUserSpotBalances(params);
1446
+ //
1447
+ // {
1448
+ // "status": "OK",
1449
+ // "data": [
1450
+ // {
1451
+ // "accountId": 123,
1452
+ // "asset": "USDC",
1453
+ // "balance": "13500",
1454
+ // "indexPrice": "1",
1455
+ // "notionalValue": "13500",
1456
+ // "contributionFactor": "1",
1457
+ // "equityContribution": "13500",
1458
+ // "availableToWithdraw": "100",
1459
+ // "updatedAt": 1701563440
1460
+ // },
1461
+ // {
1462
+ // "accountId": 123,
1463
+ // "asset": "BTC",
1464
+ // "balance": "0.5",
1465
+ // "indexPrice": "65000",
1466
+ // "notionalValue": "32500",
1467
+ // "contributionFactor": "0.95",
1468
+ // "equityContribution": "30875",
1469
+ // "availableToWithdraw": "0.5",
1470
+ // "updatedAt": 1701563440
1471
+ // }
1472
+ // ]
1473
+ // }
1474
+ //
1475
+ const data = this.safeList(response, 'data', []);
1476
+ return this.parseBalance(data);
1477
+ }
1478
+ parseBalance(response) {
1479
+ const result = { 'info': response };
1480
+ for (let i = 0; i < response.length; i++) {
1481
+ const balance = this.safeDict(response, i, {});
1482
+ const currencyId = this.safeString(balance, 'asset');
1483
+ const code = this.safeCurrencyCode(currencyId);
1484
+ const account = this.account();
1485
+ account['free'] = this.safeString(balance, 'availableToWithdraw');
1486
+ account['total'] = this.safeString(balance, 'balance');
1487
+ result[code] = account;
1488
+ }
1489
+ return this.safeBalance(result);
1490
+ }
1491
+ /**
1492
+ * @method
1493
+ * @name extended#fetchAccount
1494
+ * @description fetch the current authenticated sub-account
1495
+ * @see https://api.docs.extended.exchange/#get-account-details
1496
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1497
+ * @returns {object} an [account structure]{@link https://docs.ccxt.com/#/?id=account-structure}
1498
+ */
1499
+ async fetchAccount(params = {}) {
1500
+ const response = await this.v1PrivateGetUserAccountInfo(params);
1501
+ //
1502
+ // {
1503
+ // "status": "OK",
1504
+ // "data": {
1505
+ // "accountId": 3342,
1506
+ // "description": "Main account",
1507
+ // "accountIndex": 0,
1508
+ // "status": "ACTIVE",
1509
+ // "l2Key": "0x...",
1510
+ // "l2Vault": "500343",
1511
+ // "bridgeStarknetAddress": "0x...",
1512
+ // "apiKeys": [
1513
+ // "..."
1514
+ // ],
1515
+ // "accountIndexForKeyGeneration": 0
1516
+ // }
1517
+ // }
1518
+ //
1519
+ const data = this.safeDict(response, 'data', {});
1520
+ return this.parseAccount(data);
1521
+ }
1522
+ /**
1523
+ * @method
1524
+ * @name extended#fetchAccounts
1525
+ * @description fetch the current authenticated sub-account, extended private endpoints only return records for the authenticated sub-account
1526
+ * @see https://api.docs.extended.exchange/#get-sub-accounts
1527
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1528
+ * @returns {object[]} a list of [account structures]{@link https://docs.ccxt.com/#/?id=account-structure}
1529
+ */
1530
+ async fetchAccounts(params = {}) {
1531
+ const response = await this.v1PrivateGetUserAccounts(params);
1532
+ //
1533
+ // {
1534
+ // "status": "OK",
1535
+ // "data": [{
1536
+ // "accountId": 123,
1537
+ // "description": "Main",
1538
+ // "accountIndex": 0,
1539
+ // "status": "ACTIVE",
1540
+ // "l2Key": "0x123",
1541
+ // "l2Vault": "321",
1542
+ // "bridgeStarknetAddress": "0xabc",
1543
+ // "accountIndexForKeyGeneration": 0
1544
+ // }, {
1545
+ // "accountId": 999,
1546
+ // "description": "Vault Balance",
1547
+ // "accountIndex": 1001,
1548
+ // "status": "ACTIVE",
1549
+ // "l2Key": "0x123",
1550
+ // "l2Vault": "999",
1551
+ // "bridgeStarknetAddress": "0xabc",
1552
+ // "accountIndexForKeyGeneration": 0
1553
+ // }
1554
+ // ]}
1555
+ //
1556
+ const data = this.safeList(response, 'data', []);
1557
+ return this.parseAccounts(data);
1558
+ }
1559
+ parseAccount(account) {
1560
+ const accountIndex = this.safeInteger(account, 'accountIndex');
1561
+ let type = undefined;
1562
+ if (accountIndex !== undefined) {
1563
+ type = (accountIndex === 0) ? 'main' : 'subaccount';
1564
+ }
1565
+ return {
1566
+ 'id': this.safeString2(account, 'accountId', 'id'),
1567
+ 'type': type,
1568
+ 'code': undefined,
1569
+ 'info': account,
1570
+ };
1571
+ }
1572
+ /**
1573
+ * @method
1574
+ * @name extended#fetchLedger
1575
+ * @description fetch the history of changes, actions done by the user or operations that altered the balance of the user
1576
+ * @see https://api.docs.extended.exchange/#get-deposits-withdrawals-transfers-history
1577
+ * @param {string} [code] unified currency code
1578
+ * @param {int} [since] timestamp in ms of the earliest ledger entry
1579
+ * @param {int} [limit] max number of ledger entries to return
1580
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1581
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1582
+ * @returns {object[]} a list of [ledger structures]{@link https://docs.ccxt.com/#/?id=ledger}
1583
+ */
1584
+ async fetchLedger(code = undefined, since = undefined, limit = undefined, params = {}) {
1585
+ await this.loadMarkets();
1586
+ let paginate = false;
1587
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchLedger', 'paginate');
1588
+ if (paginate) {
1589
+ return await this.fetchPaginatedCallCursor('fetchLedger', code, since, limit, params, 'cursor', 'cursor', undefined, 50);
1590
+ }
1591
+ let currency = undefined;
1592
+ if (code !== undefined) {
1593
+ currency = this.currency(code);
1594
+ }
1595
+ const request = {};
1596
+ if (limit !== undefined) {
1597
+ request['limit'] = limit;
1598
+ }
1599
+ const response = await this.v1PrivateGetUserAssetOperations(this.extend(request, params));
1600
+ const data = this.safeList(response, 'data', []);
1601
+ const pagination = this.safeDict(response, 'pagination', {});
1602
+ const cursor = this.safeString(pagination, 'cursor');
1603
+ const result = [];
1604
+ const dataLength = data.length;
1605
+ for (let i = 0; i < dataLength; i++) {
1606
+ let entry = data[i];
1607
+ if ((cursor !== undefined) && (i === dataLength - 1)) {
1608
+ entry = this.extend(entry, { 'cursor': cursor });
1609
+ }
1610
+ result.push(entry);
1611
+ }
1612
+ return this.parseLedger(result, currency, since, limit);
1613
+ }
1614
+ parseLedgerEntry(item, currency = undefined) {
1615
+ //
1616
+ // {
1617
+ // "id": "1951255127004282880",
1618
+ // "type": "TRANSFER",
1619
+ // "status": "COMPLETED",
1620
+ // "amount": "-3.0000000000000000",
1621
+ // "fee": "0",
1622
+ // "asset": 1,
1623
+ // "time": 1754050449502,
1624
+ // "accountId": 100009,
1625
+ // "counterpartyAccountId": 100023
1626
+ // }
1627
+ //
1628
+ const timestamp = this.safeInteger(item, 'time');
1629
+ const assetId = this.safeString(item, 'asset');
1630
+ const code = this.getExtendedCurrencyCodeById(assetId, currency);
1631
+ const ledgerCurrency = this.safeCurrency(code, currency);
1632
+ const amountString = this.safeString(item, 'amount');
1633
+ let direction = undefined;
1634
+ if (amountString !== undefined) {
1635
+ direction = Precise["default"].stringLt(amountString, '0') ? 'out' : 'in';
1636
+ }
1637
+ let fee = undefined;
1638
+ const feeCost = this.safeString(item, 'fee');
1639
+ if (feeCost !== undefined) {
1640
+ fee = {
1641
+ 'currency': code,
1642
+ 'cost': this.parseNumber(Precise["default"].stringAbs(feeCost)),
1643
+ };
1644
+ }
1645
+ return this.safeLedgerEntry({
1646
+ 'info': item,
1647
+ 'id': this.safeString(item, 'id'),
1648
+ 'timestamp': timestamp,
1649
+ 'datetime': this.iso8601(timestamp),
1650
+ 'direction': direction,
1651
+ 'account': this.safeString(item, 'accountId'),
1652
+ 'referenceId': this.safeString(item, 'transactionHash'),
1653
+ 'referenceAccount': this.safeString(item, 'counterpartyAccountId'),
1654
+ 'type': this.parseTransactionType(this.safeString(item, 'type')),
1655
+ 'currency': code,
1656
+ 'amount': (amountString === undefined) ? undefined : this.parseNumber(Precise["default"].stringAbs(amountString)),
1657
+ 'before': undefined,
1658
+ 'after': undefined,
1659
+ 'status': this.parseTransactionStatus(this.safeString(item, 'status')),
1660
+ 'fee': fee,
1661
+ }, ledgerCurrency);
1662
+ }
1663
+ /**
1664
+ * @method
1665
+ * @name extended#fetchTransactions
1666
+ * @description fetch history of deposits, withdrawals, and transfers
1667
+ * @see https://api.docs.extended.exchange/#get-deposits-withdrawals-transfers-history
1668
+ * @param {string} [code] unified currency code
1669
+ * @param {int} [since] the earliest time in ms to fetch transactions for
1670
+ * @param {int} [limit] the maximum number of transaction structures to retrieve
1671
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1672
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1673
+ * @returns {Transaction[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
1674
+ */
1675
+ async fetchTransactions(code = undefined, since = undefined, limit = undefined, params = {}) {
1676
+ await this.loadMarkets();
1677
+ let paginate = false;
1678
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchTransactions', 'paginate');
1679
+ if (paginate) {
1680
+ return await this.fetchPaginatedCallCursor('fetchTransactions', code, since, limit, params, 'cursor', 'cursor', undefined, 50);
1681
+ }
1682
+ let currency = undefined;
1683
+ if (code !== undefined) {
1684
+ currency = this.currency(code);
1685
+ }
1686
+ const request = {};
1687
+ if (limit !== undefined) {
1688
+ request['limit'] = limit;
1689
+ }
1690
+ const response = await this.v1PrivateGetUserAssetOperations(this.extend(request, params));
1691
+ //
1692
+ // {
1693
+ // "status": "OK",
1694
+ // "data": [
1695
+ // {
1696
+ // "id": "1951255127004282880",
1697
+ // "type": "TRANSFER",
1698
+ // "status": "COMPLETED",
1699
+ // "amount": "-3.0000000000000000",
1700
+ // "fee": "0",
1701
+ // "asset": 1,
1702
+ // "time": 1754050449502,
1703
+ // "accountId": 100009,
1704
+ // "counterpartyAccountId": 100023
1705
+ // }
1706
+ // ],
1707
+ // "pagination": {
1708
+ // "cursor": 1951255127004282880,
1709
+ // "count": 1
1710
+ // }
1711
+ // }
1712
+ //
1713
+ const data = this.safeList(response, 'data', []);
1714
+ const pagination = this.safeDict(response, 'pagination', {});
1715
+ const cursor = this.safeString(pagination, 'cursor');
1716
+ const result = [];
1717
+ const dataLength = data.length;
1718
+ for (let i = 0; i < dataLength; i++) {
1719
+ let entry = data[i];
1720
+ if ((cursor !== undefined) && (i === dataLength - 1)) {
1721
+ entry = this.extend(entry, { 'cursor': cursor });
1722
+ }
1723
+ result.push(entry);
1724
+ }
1725
+ return this.parseTransactions(result, currency, since, limit);
1726
+ }
1727
+ /**
1728
+ * @method
1729
+ * @name extended#fetchDeposits
1730
+ * @description fetch all deposits made to an account
1731
+ * @see https://api.docs.extended.exchange/#get-deposits-withdrawals-transfers-history
1732
+ * @param {string} [code] unified currency code
1733
+ * @param {int} [since] the earliest time in ms to fetch deposits for
1734
+ * @param {int} [limit] the maximum number of deposit structures to retrieve
1735
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1736
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1737
+ * @returns {Transaction[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
1738
+ */
1739
+ async fetchDeposits(code = undefined, since = undefined, limit = undefined, params = {}) {
1740
+ return await this.fetchTransactions(code, since, limit, this.extend({ 'type': 'DEPOSIT' }, params));
1741
+ }
1742
+ /**
1743
+ * @method
1744
+ * @name extended#fetchWithdrawals
1745
+ * @description fetch all withdrawals made from an account
1746
+ * @see https://api.docs.extended.exchange/#get-deposits-withdrawals-transfers-history
1747
+ * @param {string} [code] unified currency code
1748
+ * @param {int} [since] the earliest time in ms to fetch withdrawals for
1749
+ * @param {int} [limit] the maximum number of withdrawal structures to retrieve
1750
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1751
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1752
+ * @returns {Transaction[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
1753
+ */
1754
+ async fetchWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) {
1755
+ return await this.fetchTransactions(code, since, limit, this.extend({ 'type': 'WITHDRAWAL' }, params));
1756
+ }
1757
+ /**
1758
+ * @method
1759
+ * @name extended#withdraw
1760
+ * @description make a Starknet withdrawal
1761
+ * @see https://api.docs.extended.exchange/#withdrawals
1762
+ * @param {string} code unified currency code
1763
+ * @param {float} amount the amount to withdraw
1764
+ * @param {string} address the Starknet address to withdraw to
1765
+ * @param {string} tag unused
1766
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1767
+ * @param {string} [params.chainId] only STRK is supported
1768
+ * @param {int} [params.settlementExpiration] settlement expiration timestamp in seconds, defaults to now + 14 days + 60 seconds
1769
+ * @returns {object} a [transaction structure]{@link https://docs.ccxt.com/?id=transaction-structure}
1770
+ */
1771
+ async withdraw(code, amount, address, tag = undefined, params = {}) {
1772
+ this.checkRequiredCredentials();
1773
+ await this.loadMarkets();
1774
+ const currency = this.currency(code);
1775
+ const chainId = this.safeStringUpper2(params, 'chainId', 'network', 'STRK');
1776
+ if (chainId !== 'STRK') {
1777
+ throw new errors.BadRequest(this.id + ' withdraw() only supports Starknet withdrawals with chainId STRK');
1778
+ }
1779
+ if (address.length <= 42) {
1780
+ throw new errors.BadRequest(this.id + ' withdraw() requires a Starknet address for STRK withdrawals, EVM withdrawals require the bridge quote flow');
1781
+ }
1782
+ const account = await this.fetchExtendedAccount();
1783
+ const amountString = this.currencyToPrecision(code, amount);
1784
+ const accountId = this.safeString(account, 'accountId');
1785
+ const settlement = this.createWithdrawalSettlementData(address, amountString, currency, account, params);
1786
+ const request = {
1787
+ 'accountId': accountId,
1788
+ 'amount': amountString,
1789
+ 'chainId': chainId,
1790
+ 'asset': currency['id'],
1791
+ 'settlement': settlement,
1792
+ };
1793
+ params = this.omit(params, ['chainId', 'network', 'settlementExpiration', 'nonce', 'recipient', 'positionId', 'l2Vault', 'collateralId', 'resolution']);
1794
+ const response = await this.v1PrivatePostUserWithdrawal(this.extend(request, params));
1795
+ //
1796
+ // {
1797
+ // "status": "OK",
1798
+ // "data": 1820796462590083072
1799
+ // }
1800
+ //
1801
+ const now = this.milliseconds();
1802
+ return {
1803
+ 'info': response,
1804
+ 'id': this.safeString(response, 'data'),
1805
+ 'txid': undefined,
1806
+ 'timestamp': now,
1807
+ 'datetime': this.iso8601(now),
1808
+ 'address': address,
1809
+ 'addressFrom': undefined,
1810
+ 'addressTo': address,
1811
+ 'tag': tag,
1812
+ 'tagFrom': undefined,
1813
+ 'tagTo': tag,
1814
+ 'type': 'withdrawal',
1815
+ 'amount': this.parseNumber(amountString),
1816
+ 'currency': currency['code'],
1817
+ 'status': 'pending',
1818
+ 'updated': now,
1819
+ 'fee': undefined,
1820
+ 'network': chainId,
1821
+ 'comment': undefined,
1822
+ 'internal': false,
1823
+ };
1824
+ }
1825
+ /**
1826
+ * @method
1827
+ * @name extended#fetchTransfers
1828
+ * @description fetch a history of internal transfers made on an account
1829
+ * @see https://api.docs.extended.exchange/#get-deposits-withdrawals-transfers-history
1830
+ * @param {string} [code] unified currency code
1831
+ * @param {int} [since] the earliest time in ms to fetch transfers for
1832
+ * @param {int} [limit] the maximum number of transfer structures to retrieve
1833
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1834
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1835
+ * @returns {TransferEntry[]} a list of [transfer structures]{@link https://docs.ccxt.com/#/?id=transfer-structure}
1836
+ */
1837
+ async fetchTransfers(code = undefined, since = undefined, limit = undefined, params = {}) {
1838
+ await this.loadMarkets();
1839
+ let paginate = false;
1840
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchTransfers', 'paginate');
1841
+ if (paginate) {
1842
+ return await this.fetchPaginatedCallCursor('fetchTransfers', code, since, limit, params, 'cursor', 'cursor', undefined, 50);
1843
+ }
1844
+ let currency = undefined;
1845
+ if (code !== undefined) {
1846
+ currency = this.currency(code);
1847
+ }
1848
+ const request = {
1849
+ 'type': 'TRANSFER',
1850
+ };
1851
+ if (limit !== undefined) {
1852
+ request['limit'] = limit;
1853
+ }
1854
+ const response = await this.v1PrivateGetUserAssetOperations(this.extend(request, params));
1855
+ const data = this.safeList(response, 'data', []);
1856
+ const pagination = this.safeDict(response, 'pagination', {});
1857
+ const cursor = this.safeString(pagination, 'cursor');
1858
+ const result = [];
1859
+ const dataLength = data.length;
1860
+ for (let i = 0; i < dataLength; i++) {
1861
+ let entry = data[i];
1862
+ if ((cursor !== undefined) && (i === dataLength - 1)) {
1863
+ entry = this.extend(entry, { 'cursor': cursor });
1864
+ }
1865
+ result.push(entry);
1866
+ }
1867
+ return this.parseTransfers(result, currency, since, limit);
1868
+ }
1869
+ /**
1870
+ * @method
1871
+ * @name extended#transfer
1872
+ * @description transfer collateral between sub-accounts associated with the same wallet
1873
+ * @see https://api.docs.extended.exchange/#create-transfer
1874
+ * @param {string} code unified currency code
1875
+ * @param {float} amount the amount to transfer
1876
+ * @param {string} fromAccount source account id, defaults to the authenticated account id
1877
+ * @param {string} toAccount destination account id
1878
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1879
+ * @param {string} params.toVault destination account L2 vault
1880
+ * @param {string} params.toL2Key destination account L2 public key
1881
+ * @param {int} [params.settlementExpiration] settlement expiration timestamp in seconds, defaults to now + 21 days
1882
+ * @returns {object} a [transfer structure]{@link https://docs.ccxt.com/#/?id=transfer-structure}
1883
+ */
1884
+ async transfer(code, amount, fromAccount, toAccount, params = {}) {
1885
+ this.checkRequiredCredentials();
1886
+ await this.loadMarkets();
1887
+ const currency = this.currency(code);
1888
+ const account = await this.fetchExtendedAccount();
1889
+ const currentAccountId = this.safeString(account, 'accountId');
1890
+ if (fromAccount === undefined) {
1891
+ fromAccount = currentAccountId;
1892
+ }
1893
+ else if (fromAccount !== currentAccountId) {
1894
+ throw new errors.BadRequest(this.id + ' transfer() can only transfer from the authenticated account');
1895
+ }
1896
+ const toVault = this.safeString2(params, 'toVault', 'receiverPositionId');
1897
+ const toL2Key = this.safeString2(params, 'toL2Key', 'receiverPublicKey');
1898
+ if ((toAccount === undefined) || (toVault === undefined) || (toL2Key === undefined)) {
1899
+ throw new errors.ArgumentsRequired(this.id + ' transfer() requires a toAccount argument and params["toVault"] and params["toL2Key"]');
1900
+ }
1901
+ const amountString = this.currencyToPrecision(code, amount);
1902
+ const settlement = this.createTransferSettlementData(amountString, currency, account, toVault, toL2Key, params);
1903
+ const request = {
1904
+ 'fromAccount': fromAccount,
1905
+ 'toAccount': toAccount,
1906
+ 'amount': amountString,
1907
+ 'transferredAsset': currency['id'],
1908
+ 'settlement': settlement,
1909
+ };
1910
+ params = this.omit(params, ['fromVault', 'senderPositionId', 'fromL2Key', 'senderPublicKey', 'toVault', 'receiverPositionId', 'toL2Key', 'receiverPublicKey', 'settlementExpiration', 'nonce', 'assetId', 'collateralId', 'resolution']);
1911
+ const response = await this.v1PrivatePostUserTransfer(this.extend(request, params));
1912
+ //
1913
+ // {
1914
+ // "status": "OK",
1915
+ // "data": {
1916
+ // "validSignature": true,
1917
+ // "id": 1820778187672010752
1918
+ // }
1919
+ // }
1920
+ //
1921
+ const data = this.safeDict(response, 'data', {});
1922
+ const validSignature = this.safeBool(data, 'validSignature');
1923
+ const now = this.milliseconds();
1924
+ let status = 'pending';
1925
+ if (validSignature !== undefined) {
1926
+ status = validSignature ? 'ok' : 'failed';
1927
+ }
1928
+ return {
1929
+ 'info': response,
1930
+ 'id': this.safeString(data, 'id'),
1931
+ 'timestamp': now,
1932
+ 'datetime': this.iso8601(now),
1933
+ 'currency': currency['code'],
1934
+ 'amount': this.parseNumber(amountString),
1935
+ 'fromAccount': fromAccount,
1936
+ 'toAccount': toAccount,
1937
+ 'status': status,
1938
+ };
1939
+ }
1940
+ parseTransfer(transfer, currency = undefined) {
1941
+ const timestamp = this.safeInteger(transfer, 'time');
1942
+ const assetId = this.safeString(transfer, 'asset');
1943
+ const code = this.getExtendedCurrencyCodeById(assetId, currency);
1944
+ const amountString = this.safeString(transfer, 'amount');
1945
+ const amount = (amountString === undefined) ? undefined : this.parseNumber(Precise["default"].stringAbs(amountString));
1946
+ const accountId = this.safeString(transfer, 'accountId');
1947
+ const counterpartyAccountId = this.safeString(transfer, 'counterpartyAccountId');
1948
+ let fromAccount = accountId;
1949
+ let toAccount = counterpartyAccountId;
1950
+ if ((amountString !== undefined) && !Precise["default"].stringLt(amountString, '0')) {
1951
+ fromAccount = counterpartyAccountId;
1952
+ toAccount = accountId;
1953
+ }
1954
+ const validSignature = this.safeBool(transfer, 'validSignature');
1955
+ let status = undefined;
1956
+ if (validSignature !== undefined) {
1957
+ status = validSignature ? 'ok' : 'failed';
1958
+ }
1959
+ else {
1960
+ status = this.parseTransactionStatus(this.safeString(transfer, 'status'));
1961
+ }
1962
+ return {
1963
+ 'info': transfer,
1964
+ 'id': this.safeString(transfer, 'id'),
1965
+ 'timestamp': timestamp,
1966
+ 'datetime': this.iso8601(timestamp),
1967
+ 'currency': code,
1968
+ 'amount': amount,
1969
+ 'fromAccount': fromAccount,
1970
+ 'toAccount': toAccount,
1971
+ 'status': status,
1972
+ };
1973
+ }
1974
+ getExtendedCurrencyCodeById(assetId, currency = undefined) {
1975
+ if (assetId === undefined) {
1976
+ return this.safeString(currency, 'code');
1977
+ }
1978
+ const currenciesByNumericId = this.safeDict(this.options, 'currenciesByNumericId', {});
1979
+ const currencyByNumericId = this.safeDict(currenciesByNumericId, assetId);
1980
+ if (currencyByNumericId !== undefined) {
1981
+ return this.safeString(currencyByNumericId, 'code');
1982
+ }
1983
+ if (currency !== undefined) {
1984
+ return currency['code'];
1985
+ }
1986
+ let code = this.safeCurrencyCode(assetId);
1987
+ if (code === 'USD') {
1988
+ code = 'USDC';
1989
+ }
1990
+ return code;
1991
+ }
1992
+ parseTransactionStatus(status) {
1993
+ const statuses = {
1994
+ 'CREATED': 'pending',
1995
+ 'IN_PROGRESS': 'pending',
1996
+ 'COMPLETED': 'ok',
1997
+ 'REJECTED': 'failed',
1998
+ };
1999
+ return this.safeString(statuses, status, status);
2000
+ }
2001
+ parseTransactionType(type) {
2002
+ const types = {
2003
+ 'DEPOSIT': 'deposit',
2004
+ 'WITHDRAWAL': 'withdrawal',
2005
+ 'TRANSFER': 'transfer',
2006
+ 'CLAIM': 'claim',
2007
+ };
2008
+ return this.safeString(types, type, type);
2009
+ }
2010
+ parseTransaction(transaction, currency = undefined) {
2011
+ //
2012
+ // {
2013
+ // "id": "1951255127004282880",
2014
+ // "type": "TRANSFER",
2015
+ // "status": "COMPLETED",
2016
+ // "amount": "-3.0000000000000000",
2017
+ // "fee": "0",
2018
+ // "asset": 1,
2019
+ // "time": 1754050449502,
2020
+ // "accountId": 100009,
2021
+ // "counterpartyAccountId": 100023
2022
+ // }
2023
+ //
2024
+ const timestamp = this.safeInteger(transaction, 'time');
2025
+ const assetId = this.safeString(transaction, 'asset');
2026
+ const code = this.getExtendedCurrencyCodeById(assetId, currency);
2027
+ const amountString = this.safeString(transaction, 'amount');
2028
+ const amount = (amountString === undefined) ? undefined : this.parseNumber(Precise["default"].stringAbs(amountString));
2029
+ let fee = undefined;
2030
+ const feeCost = this.safeString(transaction, 'fee');
2031
+ if (feeCost !== undefined) {
2032
+ fee = {
2033
+ 'currency': code,
2034
+ 'cost': this.parseNumber(Precise["default"].stringAbs(feeCost)),
2035
+ };
2036
+ }
2037
+ const transactionType = this.parseTransactionType(this.safeString(transaction, 'type'));
2038
+ const network = this.safeString(transaction, 'chain');
2039
+ return {
2040
+ 'info': transaction,
2041
+ 'id': this.safeString(transaction, 'id'),
2042
+ 'txid': this.safeString(transaction, 'transactionHash'),
2043
+ 'timestamp': timestamp,
2044
+ 'datetime': this.iso8601(timestamp),
2045
+ 'address': undefined,
2046
+ 'addressFrom': undefined,
2047
+ 'addressTo': undefined,
2048
+ 'tag': undefined,
2049
+ 'tagFrom': undefined,
2050
+ 'tagTo': undefined,
2051
+ 'type': transactionType,
2052
+ 'amount': amount,
2053
+ 'currency': code,
2054
+ 'status': this.parseTransactionStatus(this.safeString(transaction, 'status')),
2055
+ 'updated': timestamp,
2056
+ 'fee': fee,
2057
+ 'network': network,
2058
+ 'comment': undefined,
2059
+ 'internal': (transactionType === 'transfer'),
2060
+ };
2061
+ }
2062
+ /**
2063
+ * @method
2064
+ * @name extended#fetchTradingFee
2065
+ * @description fetch the trading fees for a market
2066
+ * @see https://api.docs.extended.exchange/#get-fees
2067
+ * @param {string} symbol unified market symbol
2068
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2069
+ * @param {string} [params.builderId] builder client id
2070
+ * @returns {object} a [fee structure]{@link https://docs.ccxt.com/?id=fee-structure}
2071
+ */
2072
+ async fetchTradingFee(symbol, params = {}) {
2073
+ await this.loadMarkets();
2074
+ const market = this.market(symbol);
2075
+ const request = {
2076
+ 'market': market['id'],
2077
+ };
2078
+ const response = await this.v1PrivateGetUserFees(this.extend(request, params));
2079
+ //
2080
+ // {
2081
+ // "status": "OK",
2082
+ // "data": [
2083
+ // {
2084
+ // "market": "BTC-USD",
2085
+ // "makerFeeRate": "0.00000",
2086
+ // "takerFeeRate": "0.00025",
2087
+ // "builderFeeRate": "0.0001"
2088
+ // }
2089
+ // ]
2090
+ // }
2091
+ //
2092
+ const data = this.safeList(response, 'data', []);
2093
+ const first = this.safeDict(data, 0, {});
2094
+ return this.parseTradingFee(first, market);
2095
+ }
2096
+ /**
2097
+ * @method
2098
+ * @name extended#fetchTradingFees
2099
+ * @description fetch the trading fees for multiple markets
2100
+ * @see https://api.docs.extended.exchange/#get-fees
2101
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2102
+ * @param {string} [params.market] exchange market id
2103
+ * @param {string} [params.builderId] builder client id
2104
+ * @returns {object} a dictionary of [fee structures]{@link https://docs.ccxt.com/?id=fee-structure} indexed by market symbols
2105
+ */
2106
+ async fetchTradingFees(params = {}) {
2107
+ await this.loadMarkets();
2108
+ const response = await this.v1PrivateGetUserFees(params);
2109
+ //
2110
+ // {
2111
+ // "status": "OK",
2112
+ // "data": [
2113
+ // {
2114
+ // "market": "BTC-USD",
2115
+ // "makerFeeRate": "0.00000",
2116
+ // "takerFeeRate": "0.00025",
2117
+ // "builderFeeRate": "0.0001"
2118
+ // }
2119
+ // ]
2120
+ // }
2121
+ //
2122
+ const data = this.safeList(response, 'data', []);
2123
+ const result = {};
2124
+ for (let i = 0; i < data.length; i++) {
2125
+ const fee = this.safeDict(data, i, {});
2126
+ const parsed = this.parseTradingFee(fee);
2127
+ const symbol = this.safeString(parsed, 'symbol');
2128
+ result[symbol] = parsed;
2129
+ }
2130
+ return result;
2131
+ }
2132
+ parseTradingFee(fee, market = undefined) {
2133
+ //
2134
+ // {
2135
+ // "market": "BTC-USD",
2136
+ // "makerFeeRate": "0.00000",
2137
+ // "takerFeeRate": "0.00025",
2138
+ // "builderFeeRate": "0.0001"
2139
+ // }
2140
+ //
2141
+ const marketId = this.safeString(fee, 'market');
2142
+ market = this.safeMarket(marketId, market);
2143
+ return {
2144
+ 'info': fee,
2145
+ 'symbol': market['symbol'],
2146
+ 'maker': this.safeNumber(fee, 'makerFeeRate'),
2147
+ 'taker': this.safeNumber(fee, 'takerFeeRate'),
2148
+ 'percentage': true,
2149
+ 'tierBased': undefined,
2150
+ };
2151
+ }
2152
+ /**
2153
+ * @method
2154
+ * @name extended#fetchLeverage
2155
+ * @description fetch the set leverage for a market
2156
+ * @see https://api.docs.extended.exchange/#get-leverage
2157
+ * @param {string} symbol unified market symbol
2158
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2159
+ * @returns {object} a [leverage structure]{@link https://docs.ccxt.com/#/?id=leverage-structure}
2160
+ */
2161
+ async fetchLeverage(symbol, params = {}) {
2162
+ await this.loadMarkets();
2163
+ const market = this.market(symbol);
2164
+ const request = {
2165
+ 'market': market['id'],
2166
+ };
2167
+ const response = await this.v1PrivateGetUserLeverage(this.extend(request, params));
2168
+ //
2169
+ // {
2170
+ // "status": "OK",
2171
+ // "data": [
2172
+ // {
2173
+ // "market": "SOL-USD",
2174
+ // "leverage": "10"
2175
+ // }
2176
+ // ]
2177
+ // }
2178
+ //
2179
+ const data = this.safeList(response, 'data', []);
2180
+ return this.parseLeverage(this.safeDict(data, 0), market);
2181
+ }
2182
+ /**
2183
+ * @method
2184
+ * @name extended#setLeverage
2185
+ * @description set the level of leverage for a market
2186
+ * @see https://api.docs.extended.exchange/#update-leverage
2187
+ * @param {int} leverage the rate of leverage
2188
+ * @param {string} symbol unified market symbol
2189
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2190
+ * @returns {object} response from the exchange
2191
+ */
2192
+ async setLeverage(leverage, symbol = undefined, params = {}) {
2193
+ if (symbol === undefined) {
2194
+ throw new errors.ArgumentsRequired(this.id + ' setLeverage() requires a symbol argument');
2195
+ }
2196
+ await this.loadMarkets();
2197
+ const market = this.market(symbol);
2198
+ const request = {
2199
+ 'market': market['id'],
2200
+ 'leverage': this.numberToString(leverage),
2201
+ };
2202
+ const response = await this.v1PrivatePatchUserLeverage(this.extend(request, params));
2203
+ //
2204
+ // {
2205
+ // "status": "OK",
2206
+ // "data": {}
2207
+ // }
2208
+ //
2209
+ const data = this.safeDict(response, 'data', {});
2210
+ return this.parseLeverage(data, market);
2211
+ }
2212
+ parseLeverage(leverage, market = undefined) {
2213
+ //
2214
+ // {
2215
+ // "market": "BTC-USD",
2216
+ // "leverage": "10"
2217
+ // }
2218
+ //
2219
+ const marketId = this.safeString(leverage, 'market');
2220
+ market = this.safeMarket(marketId, market);
2221
+ const leverageValue = this.safeNumber(leverage, 'leverage');
2222
+ return {
2223
+ 'info': leverage,
2224
+ 'symbol': market['symbol'],
2225
+ 'marginMode': undefined,
2226
+ 'longLeverage': leverageValue,
2227
+ 'shortLeverage': leverageValue,
2228
+ };
2229
+ }
2230
+ /**
2231
+ * @method
2232
+ * @name extended#fetchPositions
2233
+ * @description fetch all open positions
2234
+ * @see https://api.docs.extended.exchange/#get-positions
2235
+ * @param {string[]|undefined} symbols list of unified market symbols
2236
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2237
+ * @returns {Position[]} a list of [position structures]{@link https://docs.ccxt.com/#/?id=position-structure}
2238
+ */
2239
+ async fetchPositions(symbols = undefined, params = {}) {
2240
+ await this.loadMarkets();
2241
+ const request = {};
2242
+ if (symbols !== undefined) {
2243
+ const marketIds = this.marketIds(symbols);
2244
+ request['market'] = marketIds;
2245
+ }
2246
+ const response = await this.v1PrivateGetUserPositions(this.extend(request, params));
2247
+ //
2248
+ // {
2249
+ // "status": "OK",
2250
+ // "data": [
2251
+ // {
2252
+ // "id": 1,
2253
+ // "accountId": 1,
2254
+ // "market": "BTC-USD",
2255
+ // "side": "LONG",
2256
+ // "leverage": "10",
2257
+ // "size": "0.1",
2258
+ // "value": "4000",
2259
+ // "openPrice": "39000",
2260
+ // "markPrice": "40000",
2261
+ // "liquidationPrice": "38200",
2262
+ // "margin": "20",
2263
+ // "unrealisedPnl": "1000",
2264
+ // "realisedPnl": "1.2",
2265
+ // "tpTriggerPrice": "41000",
2266
+ // "tpLimitPrice": "41500",
2267
+ // "slTriggerPrice": "39500",
2268
+ // "slLimitPrice": "39000",
2269
+ // "adl": "2.5",
2270
+ // "maxPositionSize": "0.2",
2271
+ // "createdAt": 1701563440000,
2272
+ // "updatedAt": 1701563440000
2273
+ // }
2274
+ // ]
2275
+ // }
2276
+ //
2277
+ const data = this.safeList(response, 'data', []);
2278
+ return this.parsePositions(data, symbols);
2279
+ }
2280
+ /**
2281
+ * @method
2282
+ * @name extended#fetchPosition
2283
+ * @description fetch data on an open position
2284
+ * @see https://api.docs.extended.exchange/#get-positions
2285
+ * @param {string} symbol unified market symbol of the market the position is held in
2286
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2287
+ * @returns {object} a [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
2288
+ */
2289
+ async fetchPosition(symbol, params = {}) {
2290
+ const positions = await this.fetchPositions([symbol], params);
2291
+ return this.safeDict(positions, 0);
2292
+ }
2293
+ /**
2294
+ * @method
2295
+ * @name extended#fetchPositionsHistory
2296
+ * @description fetch historical positions
2297
+ * @see https://api.docs.extended.exchange/#get-positions-history
2298
+ * @param {string[]|undefined} symbols list of unified market symbols
2299
+ * @param {int} [since] the earliest time in ms to fetch positions for
2300
+ * @param {int} [limit] the maximum number of position structures to retrieve
2301
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2302
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
2303
+ * @returns {Position[]} a list of [position structures]{@link https://docs.ccxt.com/#/?id=position-structure}
2304
+ */
2305
+ async fetchPositionsHistory(symbols = undefined, since = undefined, limit = undefined, params = {}) {
2306
+ await this.loadMarkets();
2307
+ if (typeof symbols === 'string') {
2308
+ symbols = [symbols];
2309
+ }
2310
+ let paginate = false;
2311
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchPositionsHistory', 'paginate');
2312
+ if (paginate) {
2313
+ return await this.fetchPaginatedCallCursor('fetchPositionsHistory', symbols, since, limit, params, 'cursor', 'cursor', undefined, 10000);
2314
+ }
2315
+ const request = {};
2316
+ if (symbols !== undefined) {
2317
+ const marketIds = this.marketIds(symbols);
2318
+ request['market'] = marketIds;
2319
+ }
2320
+ const response = await this.v1PrivateGetUserPositionsHistory(this.extend(request, params));
2321
+ //
2322
+ // {
2323
+ // "status": "OK",
2324
+ // "data": [
2325
+ // {
2326
+ // "id": 1784963886257016832,
2327
+ // "accountId": 1,
2328
+ // "market": "BTC-USD",
2329
+ // "side": "LONG",
2330
+ // "exitType": "TRADE",
2331
+ // "leverage": "10",
2332
+ // "size": "0.1",
2333
+ // "maxPositionSize": "0.2",
2334
+ // "openPrice": "39000",
2335
+ // "exitPrice": "40000",
2336
+ // "realisedPnl": "10",
2337
+ // "createdTime": 1701563440000,
2338
+ // "closedTime": 1701567040000
2339
+ // }
2340
+ // ],
2341
+ // "pagination": {
2342
+ // "cursor": 1784963886257016832,
2343
+ // "count": 1
2344
+ // }
2345
+ // }
2346
+ //
2347
+ const data = this.safeList(response, 'data', []);
2348
+ const pagination = this.safeDict(response, 'pagination', {});
2349
+ const cursor = this.safeString(pagination, 'cursor');
2350
+ const result = [];
2351
+ const dataLength = data.length;
2352
+ for (let i = 0; i < dataLength; i++) {
2353
+ let entry = data[i];
2354
+ if ((cursor !== undefined) && (i === dataLength - 1)) {
2355
+ entry = this.extend(entry, { 'cursor': cursor });
2356
+ }
2357
+ result.push(entry);
2358
+ }
2359
+ const positions = this.parsePositions(result, symbols);
2360
+ return this.filterBySinceLimit(positions, since, limit, 'timestamp');
2361
+ }
2362
+ parsePosition(position, market = undefined) {
2363
+ //
2364
+ // {
2365
+ // "id": 1,
2366
+ // "accountId": 1,
2367
+ // "market": "BTC-USD",
2368
+ // "side": "LONG",
2369
+ // "leverage": "10",
2370
+ // "size": "0.1",
2371
+ // "value": "4000",
2372
+ // "openPrice": "39000",
2373
+ // "markPrice": "40000",
2374
+ // "liquidationPrice": "38200",
2375
+ // "margin": "20",
2376
+ // "unrealisedPnl": "1000",
2377
+ // "realisedPnl": "1.2",
2378
+ // "tpTriggerPrice": "41000",
2379
+ // "tpLimitPrice": "41500",
2380
+ // "slTriggerPrice": "39500",
2381
+ // "slLimitPrice": "39000",
2382
+ // "adl": "2.5",
2383
+ // "maxPositionSize": "0.2",
2384
+ // "createdAt": 1701563440000,
2385
+ // "updatedAt": 1701563440000
2386
+ // }
2387
+ //
2388
+ const marketId = this.safeString(position, 'market');
2389
+ market = this.safeMarket(marketId, market);
2390
+ const timestamp = this.safeInteger2(position, 'createdAt', 'createdTime');
2391
+ let lastUpdateTimestamp = this.safeInteger2(position, 'updatedAt', 'updatedTime');
2392
+ lastUpdateTimestamp = this.safeInteger(position, 'closedTime', lastUpdateTimestamp);
2393
+ const side = this.safeStringLower(position, 'side');
2394
+ const margin = this.safeString(position, 'margin');
2395
+ return this.safePosition({
2396
+ 'info': position,
2397
+ 'id': this.safeString(position, 'id'),
2398
+ 'symbol': market['symbol'],
2399
+ 'timestamp': timestamp,
2400
+ 'datetime': this.iso8601(timestamp),
2401
+ 'lastUpdateTimestamp': lastUpdateTimestamp,
2402
+ 'initialMargin': margin,
2403
+ 'initialMarginPercentage': undefined,
2404
+ 'maintenanceMargin': undefined,
2405
+ 'maintenanceMarginPercentage': undefined,
2406
+ 'entryPrice': this.safeString(position, 'openPrice'),
2407
+ 'notional': this.safeString(position, 'value'),
2408
+ 'leverage': this.safeString(position, 'leverage'),
2409
+ 'unrealizedPnl': this.safeString(position, 'unrealisedPnl'),
2410
+ 'realizedPnl': this.safeString(position, 'realisedPnl'),
2411
+ 'contracts': this.safeString(position, 'size'),
2412
+ 'contractSize': this.safeString(market, 'contractSize'),
2413
+ 'marginRatio': undefined,
2414
+ 'liquidationPrice': this.safeString(position, 'liquidationPrice'),
2415
+ 'markPrice': this.safeString(position, 'markPrice'),
2416
+ 'lastPrice': this.safeString(position, 'exitPrice'),
2417
+ 'collateral': margin,
2418
+ 'marginMode': undefined,
2419
+ 'side': side,
2420
+ 'percentage': undefined,
2421
+ 'hedged': undefined,
2422
+ 'stopLossPrice': this.safeString(position, 'slTriggerPrice'),
2423
+ 'takeProfitPrice': this.safeString(position, 'tpTriggerPrice'),
2424
+ });
2425
+ }
2426
+ getExtendedStarkAmount(amount, resolution, roundUp = false) {
2427
+ const resolutionString = this.numberToString(resolution);
2428
+ const precise = Precise["default"].stringMul(amount, resolutionString);
2429
+ let result = this.decimalToPrecision(precise, number.TRUNCATE, 0, number.DECIMAL_PLACES, number.NO_PADDING);
2430
+ if (roundUp && Precise["default"].stringGt(precise, result)) {
2431
+ result = Precise["default"].stringAdd(result, '1');
2432
+ }
2433
+ return result;
2434
+ }
2435
+ async fetchExtendedAccount(params = {}) {
2436
+ let account = this.safeDict(this.options, 'account');
2437
+ if (account !== undefined) {
2438
+ return account;
2439
+ }
2440
+ const accountData = await this.fetchAccount(params);
2441
+ account = accountData['info'];
2442
+ this.options['account'] = account;
2443
+ return account;
2444
+ }
2445
+ createOrderSettlementData(isBuy, amountString, priceString, params = {}) {
2446
+ const totalFee = this.safeString(params, 'totalFee');
2447
+ const settlementExpiration = this.safeInteger(params, 'settlementExpiration');
2448
+ const nonce = this.safeInteger(params, 'nonce');
2449
+ const starkKey = this.safeString(params, 'starkKey');
2450
+ const collateralPosition = this.safeString(params, 'collateralPosition');
2451
+ const syntheticId = this.safeString(params, 'syntheticId');
2452
+ const collateralId = this.safeString(params, 'collateralId');
2453
+ const syntheticResolution = this.safeInteger(params, 'syntheticResolution');
2454
+ const collateralResolution = this.safeInteger(params, 'collateralResolution');
2455
+ const quoteAmount = Precise["default"].stringMul(amountString, priceString);
2456
+ const baseRoundUp = isBuy;
2457
+ const quoteRoundUp = isBuy;
2458
+ let baseAmount = this.getExtendedStarkAmount(amountString, syntheticResolution, baseRoundUp);
2459
+ let collateralAmount = this.getExtendedStarkAmount(quoteAmount, collateralResolution, quoteRoundUp);
2460
+ if (isBuy) {
2461
+ collateralAmount = Precise["default"].stringNeg(collateralAmount);
2462
+ }
2463
+ else {
2464
+ baseAmount = Precise["default"].stringNeg(baseAmount);
2465
+ }
2466
+ const feeAmount = this.getExtendedStarkAmount(Precise["default"].stringMul(totalFee, quoteAmount), collateralResolution, true);
2467
+ const settlement = {
2468
+ 'starkKey': starkKey,
2469
+ 'collateralPosition': collateralPosition,
2470
+ 'baseAssetId': syntheticId,
2471
+ 'baseAmount': baseAmount,
2472
+ 'quoteAssetId': collateralId,
2473
+ 'quoteAmount': collateralAmount,
2474
+ 'feeAssetId': collateralId,
2475
+ 'feeAmount': feeAmount,
2476
+ 'expiration': this.numberToString(settlementExpiration),
2477
+ 'salt': nonce,
2478
+ };
2479
+ const msgHash = this.getExtendedOrderMsgHash(settlement);
2480
+ const sig = JSON.parse(this.extendedStarknetSign(msgHash, this.privateKey));
2481
+ const r = this.getExtendedSignatureHex(sig[0]);
2482
+ const s = this.getExtendedSignatureHex(sig[1]);
2483
+ settlement['r'] = r;
2484
+ settlement['s'] = s;
2485
+ return settlement;
2486
+ }
2487
+ createWithdrawalSettlementData(address, amountString, currency, account, params = {}) {
2488
+ const now = this.milliseconds();
2489
+ const settlementExpiration = this.safeInteger(params, 'settlementExpiration', this.parseToInt((now + 999) / 1000) + 1209600 + 60);
2490
+ const nonce = this.safeInteger(params, 'nonce', this.nonce());
2491
+ const positionId = this.safeString2(params, 'positionId', 'l2Vault', this.safeString(account, 'l2Vault'));
2492
+ const recipient = this.safeString(params, 'recipient', address);
2493
+ const currencyInfo = this.safeDict(currency, 'info', {});
2494
+ const collateralId = this.safeString(params, 'collateralId', this.safeString2(currencyInfo, 'starkexId', 'l1Id'));
2495
+ const resolution = this.safeInteger(params, 'resolution', this.safeValue2(currencyInfo, 'starkexResolution', 'l1Resolution'));
2496
+ const starkKey = this.safeString(account, 'l2Key');
2497
+ if ((positionId === undefined) || (collateralId === undefined) || (resolution === undefined) || (starkKey === undefined)) {
2498
+ throw new errors.BadRequest(this.id + ' withdraw() requires currency starkexId/starkexResolution, account l2Vault and account l2Key');
2499
+ }
2500
+ const amount = this.getExtendedStarkAmount(amountString, resolution);
2501
+ const settlement = {
2502
+ 'recipient': recipient,
2503
+ 'positionId': positionId,
2504
+ 'collateralId': collateralId,
2505
+ 'amount': amount,
2506
+ 'expiration': {
2507
+ 'seconds': settlementExpiration,
2508
+ },
2509
+ 'salt': nonce,
2510
+ };
2511
+ const msgHash = this.getExtendedWithdrawalMsgHash(settlement, starkKey);
2512
+ const sig = JSON.parse(this.extendedStarknetSign(msgHash, this.privateKey));
2513
+ settlement['signature'] = {
2514
+ 'r': this.getExtendedSignatureHex(sig[0]),
2515
+ 's': this.getExtendedSignatureHex(sig[1]),
2516
+ };
2517
+ return settlement;
2518
+ }
2519
+ createTransferSettlementData(amountString, currency, account, toVault, toL2Key, params = {}) {
2520
+ const now = this.milliseconds();
2521
+ const settlementExpiration = this.safeInteger(params, 'settlementExpiration', this.parseToInt((now + 999) / 1000) + 1814400);
2522
+ const nonce = this.safeInteger(params, 'nonce', this.nonce());
2523
+ const fromVault = this.safeString2(params, 'fromVault', 'senderPositionId', this.safeString(account, 'l2Vault'));
2524
+ const fromL2Key = this.safeString2(params, 'fromL2Key', 'senderPublicKey', this.safeString(account, 'l2Key'));
2525
+ const currencyInfo = this.safeDict(currency, 'info', {});
2526
+ const collateralId = this.safeString2(params, 'assetId', 'collateralId', this.safeString2(currencyInfo, 'starkexId', 'l1Id'));
2527
+ const resolution = this.safeInteger(params, 'resolution', this.safeValue2(currencyInfo, 'starkexResolution', 'l1Resolution'));
2528
+ if ((fromVault === undefined) || (fromL2Key === undefined) || (collateralId === undefined) || (resolution === undefined)) {
2529
+ throw new errors.BadRequest(this.id + ' transfer() requires currency starkexId/starkexResolution, account l2Vault and account l2Key');
2530
+ }
2531
+ const transferAmount = this.getExtendedStarkAmount(amountString, resolution);
2532
+ const settlement = {
2533
+ 'amount': transferAmount,
2534
+ 'assetId': collateralId,
2535
+ 'expirationTimestamp': settlementExpiration,
2536
+ 'nonce': nonce,
2537
+ 'receiverPositionId': toVault,
2538
+ 'receiverPublicKey': toL2Key,
2539
+ 'senderPositionId': fromVault,
2540
+ 'senderPublicKey': fromL2Key,
2541
+ };
2542
+ const msgHash = this.getExtendedTransferMsgHash(settlement);
2543
+ const sig = JSON.parse(this.extendedStarknetSign(msgHash, this.privateKey));
2544
+ settlement['signature'] = {
2545
+ 'r': this.getExtendedSignatureHex(sig[0]),
2546
+ 's': this.getExtendedSignatureHex(sig[1]),
2547
+ };
2548
+ return settlement;
2549
+ }
2550
+ async createExtendedOrderRequest(symbol, type, side, amount, price = undefined, params = {}) {
2551
+ await this.loadMarkets();
2552
+ const market = this.market(symbol);
2553
+ const uppercaseType = type.toUpperCase();
2554
+ const uppercaseSide = side.toUpperCase();
2555
+ if (market['spot'] && uppercaseType !== 'LIMIT') {
2556
+ throw new errors.BadRequest(this.id + ' createOrder() supports limit orders for spot markets only');
2557
+ }
2558
+ if (!this.inArray(uppercaseType, ['LIMIT', 'MARKET', 'CONDITIONAL', 'TPSL'])) {
2559
+ throw new errors.BadRequest(this.id + ' createOrder() supports limit, market, conditional and tpsl orders only');
2560
+ }
2561
+ if (price === undefined) {
2562
+ throw new errors.ArgumentsRequired(this.id + ' createOrder() requires a price argument');
2563
+ }
2564
+ const amountString = this.amountToPrecision(symbol, amount);
2565
+ const priceString = this.priceToPrecision(symbol, price);
2566
+ const postOnly = this.isPostOnly(uppercaseType === 'MARKET', undefined, params);
2567
+ const reduceOnly = this.safeBool2(params, 'reduceOnly', 'reduce_only', false);
2568
+ let timeInForce = this.safeStringUpper(params, 'timeInForce');
2569
+ if (timeInForce === undefined) {
2570
+ timeInForce = (uppercaseType === 'MARKET') ? 'IOC' : 'GTT';
2571
+ }
2572
+ const fee = this.safeString(params, 'fee', '0.0005');
2573
+ let builderFeeRate = undefined;
2574
+ let builderId = undefined;
2575
+ if (this.isSandboxModeEnabled) {
2576
+ builderFeeRate = this.safeString2(params, 'builderFeeRate', 'defaultBuilderFeeRate');
2577
+ builderId = this.safeString2(params, 'builderId', 'defaultBuilderId');
2578
+ params = this.omit(params, ['builderFeeRate', 'defaultBuilderFeeRate', 'builderId', 'defaultBuilderId']);
2579
+ }
2580
+ else {
2581
+ [builderFeeRate, params] = this.handleOptionAndParams(params, 'createOrder', 'builderFeeRate', '0.0001');
2582
+ [builderId, params] = this.handleOptionAndParams(params, 'createOrder', 'builderId');
2583
+ }
2584
+ let totalFee = fee;
2585
+ if (builderFeeRate !== undefined) {
2586
+ totalFee = Precise["default"].stringAdd(fee, builderFeeRate);
2587
+ }
2588
+ const now = this.milliseconds();
2589
+ const expiryEpochMillis = this.safeInteger(params, 'expiryEpochMillis', now + 3600000);
2590
+ const settlementExpiration = this.safeInteger(params, 'settlementExpiration', this.parseToInt((expiryEpochMillis + 999) / 1000) + 1209600);
2591
+ const nonce = this.numberToString(this.nonce());
2592
+ const account = await this.fetchExtendedAccount();
2593
+ const starkKey = this.safeString(account, 'l2Key');
2594
+ const collateralPosition = this.safeString(account, 'l2Vault');
2595
+ const info = this.safeDict(market, 'info', {});
2596
+ const l2Config = this.safeDict(info, 'l2Config', {});
2597
+ const syntheticId = this.safeString(l2Config, 'syntheticId');
2598
+ const collateralId = this.safeString(l2Config, 'collateralId');
2599
+ const syntheticResolution = this.safeInteger(l2Config, 'syntheticResolution');
2600
+ const collateralResolution = this.safeInteger(l2Config, 'collateralResolution');
2601
+ if ((syntheticId === undefined) || (collateralId === undefined) || (syntheticResolution === undefined) || (collateralResolution === undefined)) {
2602
+ throw new errors.BadRequest(this.id + ' createOrder() requires l2Config in market info');
2603
+ }
2604
+ const settlementParams = {
2605
+ 'totalFee': totalFee,
2606
+ 'starkKey': starkKey,
2607
+ 'syntheticId': syntheticId,
2608
+ 'syntheticResolution': syntheticResolution,
2609
+ 'collateralId': collateralId,
2610
+ 'collateralResolution': collateralResolution,
2611
+ 'settlementExpiration': settlementExpiration,
2612
+ 'nonce': nonce,
2613
+ 'collateralPosition': collateralPosition,
2614
+ };
2615
+ const isBuy = (uppercaseSide === 'BUY');
2616
+ const clientOrderId = this.safeString2(params, 'clientOrderId', 'client_id', this.uuid());
2617
+ const request = {
2618
+ 'id': clientOrderId,
2619
+ 'market': market['id'],
2620
+ 'type': uppercaseType,
2621
+ 'side': uppercaseSide,
2622
+ 'qty': amountString,
2623
+ 'price': priceString,
2624
+ 'timeInForce': timeInForce,
2625
+ 'expiryEpochMillis': expiryEpochMillis,
2626
+ 'fee': fee,
2627
+ 'nonce': nonce,
2628
+ 'postOnly': postOnly,
2629
+ 'reduceOnly': reduceOnly,
2630
+ 'selfTradeProtectionLevel': 'ACCOUNT',
2631
+ };
2632
+ if (builderFeeRate !== undefined) {
2633
+ request['builderFee'] = builderFeeRate;
2634
+ }
2635
+ if (builderId !== undefined) {
2636
+ request['builderId'] = builderId;
2637
+ }
2638
+ const cancelId = this.safeString2(params, 'cancelId', 'previousOrderId');
2639
+ if (cancelId !== undefined) {
2640
+ request['cancelId'] = cancelId;
2641
+ }
2642
+ const settlement = this.createOrderSettlementData(isBuy, amountString, priceString, settlementParams);
2643
+ request['settlement'] = {
2644
+ 'signature': { 'r': settlement['r'], 's': settlement['s'] },
2645
+ 'starkKey': starkKey,
2646
+ 'collateralPosition': collateralPosition,
2647
+ };
2648
+ let triggerPriceStr = this.safeString2(params, 'triggerPrice', 'stopPrice');
2649
+ const stopLossTriggerPrice = this.safeString(params, 'stopLossPrice');
2650
+ const takeProfitTriggerPrice = this.safeString(params, 'takeProfitPrice');
2651
+ const isStopLossOrder = stopLossTriggerPrice !== undefined;
2652
+ const isTakeProfitOrder = takeProfitTriggerPrice !== undefined;
2653
+ const stopLoss = this.safeDict(params, 'stopLoss');
2654
+ const takeProfit = this.safeDict(params, 'takeProfit');
2655
+ const hasStopLoss = (stopLoss !== undefined);
2656
+ const hasTakeProfit = (takeProfit !== undefined);
2657
+ if (hasStopLoss || hasTakeProfit) {
2658
+ request['tpSlType'] = 'ORDER';
2659
+ if (hasStopLoss) {
2660
+ const stopLossTrigger = this.safeString(stopLoss, 'triggerPrice');
2661
+ const stopLossTriggerPriceType = this.safeString(stopLoss, 'triggerPriceType');
2662
+ const stopLossExecutionPrice = this.safeString(stopLoss, 'price');
2663
+ const stopLossType = this.safeString(stopLoss, 'type');
2664
+ const stopLossSettlement = this.createOrderSettlementData(!isBuy, amountString, stopLossExecutionPrice, settlementParams);
2665
+ const requestStopLoss = {
2666
+ 'triggerPrice': this.priceToPrecision(symbol, stopLossTrigger),
2667
+ 'price': this.priceToPrecision(symbol, stopLossExecutionPrice),
2668
+ 'settlement': {
2669
+ 'signature': { 'r': stopLossSettlement['r'], 's': stopLossSettlement['s'] },
2670
+ 'starkKey': starkKey,
2671
+ 'collateralPosition': collateralPosition,
2672
+ },
2673
+ };
2674
+ if (stopLossTriggerPriceType !== undefined) {
2675
+ requestStopLoss['triggerPriceType'] = stopLossTriggerPriceType;
2676
+ }
2677
+ if (stopLossType !== undefined) {
2678
+ requestStopLoss['priceType'] = stopLossType;
2679
+ }
2680
+ request['stopLoss'] = requestStopLoss;
2681
+ }
2682
+ if (hasTakeProfit) {
2683
+ const takeProfitTrigger = this.safeString(takeProfit, 'triggerPrice');
2684
+ const takeProfitTriggerPriceType = this.safeString(takeProfit, 'triggerPriceType');
2685
+ const takeProfitExecutionPrice = this.safeString(takeProfit, 'price');
2686
+ const takeProfitType = this.safeString(takeProfit, 'type');
2687
+ const takeProfitSettlement = this.createOrderSettlementData(!isBuy, amountString, takeProfitExecutionPrice, settlementParams);
2688
+ const requestTakeProfit = {
2689
+ 'triggerPrice': this.priceToPrecision(symbol, takeProfitTrigger),
2690
+ 'price': this.priceToPrecision(symbol, takeProfitExecutionPrice),
2691
+ 'settlement': {
2692
+ 'signature': { 'r': takeProfitSettlement['r'], 's': takeProfitSettlement['s'] },
2693
+ 'starkKey': starkKey,
2694
+ 'collateralPosition': collateralPosition,
2695
+ },
2696
+ };
2697
+ if (takeProfitTriggerPriceType !== undefined) {
2698
+ requestTakeProfit['triggerPriceType'] = takeProfitTriggerPriceType;
2699
+ }
2700
+ if (takeProfitType !== undefined) {
2701
+ requestTakeProfit['priceType'] = takeProfitType;
2702
+ }
2703
+ request['takeProfit'] = requestTakeProfit;
2704
+ }
2705
+ }
2706
+ else {
2707
+ if (triggerPriceStr !== undefined) {
2708
+ const triggerDirection = this.safeStringUpper(params, 'triggerDirection');
2709
+ if (triggerDirection === undefined) {
2710
+ throw new errors.ArgumentsRequired(this.id + ' createOrder() requires triggerDirection for trigger order');
2711
+ }
2712
+ const trigger = {
2713
+ 'triggerPrice': this.priceToPrecision(symbol, triggerPriceStr),
2714
+ };
2715
+ trigger['direction'] = triggerDirection;
2716
+ request['type'] = 'CONDITIONAL';
2717
+ request['trigger'] = trigger;
2718
+ }
2719
+ else if (isStopLossOrder || isTakeProfitOrder) {
2720
+ triggerPriceStr = isStopLossOrder ? stopLossTriggerPrice : takeProfitTriggerPrice;
2721
+ const trigger = {
2722
+ 'triggerPrice': this.priceToPrecision(symbol, triggerPriceStr),
2723
+ };
2724
+ if (isBuy) {
2725
+ trigger['direction'] = isStopLossOrder ? 'UP' : 'DOWN';
2726
+ }
2727
+ else {
2728
+ trigger['direction'] = isStopLossOrder ? 'DOWN' : 'UP';
2729
+ }
2730
+ request['type'] = 'CONDITIONAL';
2731
+ request['trigger'] = trigger;
2732
+ }
2733
+ }
2734
+ params = this.omit(params, ['clientOrderId', 'client_id', 'timeInForce', 'postOnly', 'reduceOnly', 'reduce_only', 'fee', 'nonce', 'expiryEpochMillis', 'settlementExpiration', 'cancelId', 'previousOrderId', 'brokerId', 'referralCode', 'triggerPrice', 'stopPrice', 'triggerDirection', 'stopLossPrice', 'takeProfitPrice', 'stopLoss', 'takeProfit']);
2735
+ return {
2736
+ 'request': this.extend(request, params),
2737
+ 'market': market,
2738
+ 'timestamp': now,
2739
+ 'clientOrderId': clientOrderId,
2740
+ 'price': priceString,
2741
+ 'amount': amountString,
2742
+ };
2743
+ }
2744
+ /**
2745
+ * @method
2746
+ * @name extended#createOrder
2747
+ * @description create a trade order
2748
+ * @see https://api.docs.extended.exchange/#create-or-edit-order
2749
+ * @param {string} symbol unified symbol of the market to create an order in
2750
+ * @param {string} type 'limit' or 'market'
2751
+ * @param {string} side 'buy' or 'sell'
2752
+ * @param {float} amount how much of currency you want to trade in units of base currency
2753
+ * @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency, required for all order types
2754
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2755
+ * @param {string} [params.clientOrderId] client order id, sent as the exchange order id
2756
+ * @param {string} [params.cancelId] previous external order id to replace
2757
+ * @param {string} [params.timeInForce] 'GTT' or 'IOC'
2758
+ * @param {boolean} [params.postOnly] true if the order should only make liquidity
2759
+ * @param {boolean} [params.reduceOnly] true if the order should only reduce a position
2760
+ * @param {string} [params.fee] max fee rate for the order, default is 0.0005
2761
+ * @param {int} [params.expiryEpochMillis] order expiration timestamp in milliseconds, default is now + 1 hour
2762
+ * @param {float} [params.triggerPrice] *swap only* The price at which a trigger order is triggered at
2763
+ * @param {float} [params.stopLossPrice] *swap only* The price at which a stop loss order is triggered at
2764
+ * @param {float} [params.takeProfitPrice] *swap only* The price at which a take profit order is triggered at
2765
+ * @param {object} [params.takeProfit] *takeProfit object in params* containing the triggerPrice at which the attached take profit order will be triggered (perpetual swap markets only)
2766
+ * @param {float} [params.takeProfit.triggerPrice] *swap only* take profit trigger price
2767
+ * @param {float} [params.takeProfit.price] *swap only* the execution price for a take profit attached to a trigger order
2768
+ * @param {string} [params.takeProfit.type] *swap only* the type for a take profit attached to a trigger order, 'LAST', 'MARK' or 'INDEX', default is ''
2769
+ * @param {object} [params.stopLoss] *stopLoss object in params* containing the triggerPrice at which the attached stop loss order will be triggered (perpetual swap markets only)
2770
+ * @param {float} [params.stopLoss.triggerPrice] *swap only* stop loss trigger price
2771
+ * @param {float} [params.stopLoss.price] *swap only* the execution price for a stop loss attached to a trigger order
2772
+ * @param {string} [params.stopLoss.type] *swap only* the type for a stop loss attached to a trigger order, 'LAST', 'MARK' or 'INDEX', default is ''
2773
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2774
+ */
2775
+ async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
2776
+ this.checkRequiredCredentials();
2777
+ const extendedOrderRequest = await this.createExtendedOrderRequest(symbol, type, side, amount, price, params);
2778
+ const request = this.safeDict(extendedOrderRequest, 'request', {});
2779
+ const response = await this.v1PrivatePostUserOrder(request);
2780
+ //
2781
+ // {
2782
+ // "status": "OK",
2783
+ // "data": {
2784
+ // "id": "2051479786538188800",
2785
+ // "externalId": "3480985089570526249141260266819446928410958787024864860785196119336740291620"
2786
+ // }
2787
+ // }
2788
+ //
2789
+ const data = this.safeDict(response, 'data', {});
2790
+ const market = extendedOrderRequest['market'];
2791
+ const now = this.safeInteger(extendedOrderRequest, 'timestamp');
2792
+ data['timestamp'] = now;
2793
+ data['status'] = 'NEW';
2794
+ return this.parseOrder(this.extend(request, data), market);
2795
+ }
2796
+ /**
2797
+ * @method
2798
+ * @name extended#editOrder
2799
+ * @description edit a trade order
2800
+ * @see https://api.docs.extended.exchange/#create-or-edit-order
2801
+ * @param {string} id order id assigned by Extended
2802
+ * @param {string} symbol unified symbol of the market to edit an order in
2803
+ * @param {string} type 'limit' or 'market'
2804
+ * @param {string} side 'buy' or 'sell'
2805
+ * @param {float} [amount] how much of currency you want to trade in units of base currency
2806
+ * @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency
2807
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2808
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2809
+ */
2810
+ async editOrder(id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
2811
+ if (id === undefined) {
2812
+ throw new errors.ArgumentsRequired(this.id + ' editOrder() requires an id argument');
2813
+ }
2814
+ let expiryEpochMillis = this.safeInteger(params, 'expiryEpochMillis');
2815
+ let postOnly = this.safeBool(params, 'postOnly');
2816
+ let reduceOnly = this.safeBool2(params, 'reduceOnly', 'reduce_only');
2817
+ let cancelId = this.safeString2(params, 'cancelId', 'previousOrderId');
2818
+ if ((amount === undefined) || (price === undefined) || (expiryEpochMillis === undefined) || (postOnly === undefined) || (reduceOnly === undefined) || (cancelId === undefined)) {
2819
+ const response = await this.v1PrivateGetUserOrdersId({ 'id': id });
2820
+ const order = this.safeDict(response, 'data', {});
2821
+ if (amount === undefined) {
2822
+ amount = this.safeNumber(order, 'qty');
2823
+ }
2824
+ if (price === undefined) {
2825
+ price = this.safeNumber(order, 'price');
2826
+ }
2827
+ if (expiryEpochMillis === undefined) {
2828
+ expiryEpochMillis = this.safeInteger(order, 'expireTime');
2829
+ }
2830
+ if (postOnly === undefined) {
2831
+ postOnly = this.safeBool(order, 'postOnly', false);
2832
+ }
2833
+ if (reduceOnly === undefined) {
2834
+ reduceOnly = this.safeBool(order, 'reduceOnly', false);
2835
+ }
2836
+ if (cancelId === undefined) {
2837
+ cancelId = this.safeString(order, 'externalId');
2838
+ }
2839
+ }
2840
+ if (amount === undefined) {
2841
+ throw new errors.ArgumentsRequired(this.id + ' editOrder() requires an amount argument or an existing order with qty');
2842
+ }
2843
+ if (price === undefined) {
2844
+ throw new errors.ArgumentsRequired(this.id + ' editOrder() requires a price argument or an existing order with price');
2845
+ }
2846
+ params = this.extend({
2847
+ 'postOnly': postOnly,
2848
+ 'reduceOnly': reduceOnly,
2849
+ }, params);
2850
+ const requestParams = this.extend(params, {
2851
+ 'cancelId': cancelId,
2852
+ 'expiryEpochMillis': expiryEpochMillis,
2853
+ });
2854
+ const extendedOrderRequest = await this.createExtendedOrderRequest(symbol, type, side, amount, price, requestParams);
2855
+ const request = this.safeDict(extendedOrderRequest, 'request', {});
2856
+ const editResponse = await this.v1PrivatePostUserOrder(request);
2857
+ //
2858
+ // {
2859
+ // "status": "OK",
2860
+ // "data": {
2861
+ // "id": "2051479786538188800",
2862
+ // "externalId": "3480985089570526249141260266819446928410958787024864860785196119336740291620"
2863
+ // }
2864
+ // }
2865
+ //
2866
+ const responseData = this.safeDict(editResponse, 'data', {});
2867
+ const market = extendedOrderRequest['market'];
2868
+ const now = this.safeInteger(extendedOrderRequest, 'timestamp');
2869
+ responseData['timestamp'] = now;
2870
+ responseData['status'] = 'NEW';
2871
+ return this.parseOrder(this.extend(request, responseData), market);
2872
+ }
2873
+ /**
2874
+ * @method
2875
+ * @name extended#cancelOrder
2876
+ * @description cancels an open order
2877
+ * @see https://api.docs.extended.exchange/#cancel-order-by-id
2878
+ * @see https://api.docs.extended.exchange/#cancel-order-by-external-id
2879
+ * @param {string} id order id assigned by Extended
2880
+ * @param {string} [symbol] unified symbol of the market the order was made in
2881
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2882
+ * @param {string} [params.clientOrderId] user-defined order id, cancels by external id
2883
+ * @returns {object} An [order structure]{@link https://docs.ccxt.com/?id=order-structure}
2884
+ */
2885
+ async cancelOrder(id, symbol = undefined, params = {}) {
2886
+ await this.loadMarkets();
2887
+ let market = undefined;
2888
+ if (symbol !== undefined) {
2889
+ market = this.market(symbol);
2890
+ }
2891
+ let response = undefined;
2892
+ const clientOrderId = this.safeString2(params, 'clientOrderId', 'client_id');
2893
+ params = this.omit(params, ['clientOrderId', 'client_id']);
2894
+ if (clientOrderId !== undefined) {
2895
+ const request = {
2896
+ 'externalId': clientOrderId,
2897
+ };
2898
+ response = await this.v1PrivateDeleteUserOrder(this.extend(request, params));
2899
+ }
2900
+ else {
2901
+ if (id === undefined) {
2902
+ throw new errors.ArgumentsRequired(this.id + ' cancelOrder() requires an id argument');
2903
+ }
2904
+ const request = {
2905
+ 'id': id,
2906
+ };
2907
+ response = await this.v1PrivateDeleteUserOrderId(this.extend(request, params));
2908
+ }
2909
+ //
2910
+ // {
2911
+ // "status": "OK"
2912
+ // }
2913
+ //
2914
+ const orderId = (clientOrderId === undefined) ? id : undefined;
2915
+ const orderSymbol = (market === undefined) ? symbol : market['symbol'];
2916
+ return this.safeOrder({
2917
+ 'info': response,
2918
+ 'id': orderId,
2919
+ 'clientOrderId': clientOrderId,
2920
+ 'timestamp': undefined,
2921
+ 'datetime': undefined,
2922
+ 'symbol': orderSymbol,
2923
+ 'status': 'canceled',
2924
+ }, market);
2925
+ }
2926
+ /**
2927
+ * @method
2928
+ * @name extended#cancelOrders
2929
+ * @description cancel multiple orders by order ids or client order ids
2930
+ * @see https://api.docs.extended.exchange/#mass-cancel
2931
+ * @param {string[]} ids order ids
2932
+ * @param {string} [symbol] unified market symbol, only used to populate the returned orders
2933
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2934
+ * @param {string[]} [params.clientOrderIds] client order ids
2935
+ * @param {string} [params.clientOrderId] single client order id
2936
+ * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/?id=order-structure}
2937
+ */
2938
+ async cancelOrders(ids, symbol = undefined, params = {}) {
2939
+ await this.loadMarkets();
2940
+ let clientOrderIds = this.safeListN(params, ['clientOrderIds', 'client_order_ids', 'externalOrderIds', 'external_order_ids']);
2941
+ const clientOrderId = this.safeString2(params, 'clientOrderId', 'client_id');
2942
+ params = this.omit(params, ['clientOrderIds', 'client_order_ids', 'clientOrderId', 'client_id', 'externalOrderIds', 'external_order_ids', 'orderIds', 'order_ids', 'markets', 'cancelAll', 'cancel_all']);
2943
+ const request = {};
2944
+ const hasOrderIds = ids !== undefined;
2945
+ if (hasOrderIds) {
2946
+ const idsLength = ids.length;
2947
+ if (idsLength > 0) {
2948
+ request['orderIds'] = ids;
2949
+ }
2950
+ }
2951
+ if (clientOrderIds === undefined && clientOrderId !== undefined) {
2952
+ clientOrderIds = [clientOrderId];
2953
+ }
2954
+ const hasClientOrderIds = clientOrderIds !== undefined;
2955
+ if (hasClientOrderIds) {
2956
+ const clientOrderIdsLength = clientOrderIds.length;
2957
+ if (clientOrderIdsLength > 0) {
2958
+ request['externalOrderIds'] = clientOrderIds;
2959
+ }
2960
+ }
2961
+ if (!hasOrderIds && !hasClientOrderIds) {
2962
+ throw new errors.ArgumentsRequired(this.id + ' cancelOrders() requires an ids argument or clientOrderIds parameter');
2963
+ }
2964
+ await this.v1PrivatePostUserOrderMassCancel(this.extend(request, params));
2965
+ //
2966
+ // {
2967
+ // "status": "OK",
2968
+ // "data": {}
2969
+ // }
2970
+ //
2971
+ return [];
2972
+ }
2973
+ /**
2974
+ * @method
2975
+ * @name extended#cancelAllOrders
2976
+ * @description cancels all open orders, optionally filtered by symbol
2977
+ * @see https://api.docs.extended.exchange/#mass-cancel
2978
+ * @param {string} [symbol] unified market symbol of the market to cancel orders in
2979
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2980
+ * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/?id=order-structure}
2981
+ */
2982
+ async cancelAllOrders(symbol = undefined, params = {}) {
2983
+ await this.loadMarkets();
2984
+ const request = {
2985
+ 'cancelAll': true,
2986
+ };
2987
+ let market = undefined;
2988
+ if (symbol !== undefined) {
2989
+ market = this.market(symbol);
2990
+ request['markets'] = [market['id']];
2991
+ }
2992
+ await this.v1PrivatePostUserOrderMassCancel(this.extend(request, params));
2993
+ //
2994
+ // {
2995
+ // "status": "OK",
2996
+ // "data": {}
2997
+ // }
2998
+ //
2999
+ return [];
3000
+ }
3001
+ /**
3002
+ * @method
3003
+ * @name extended#cancelAllOrdersAfter
3004
+ * @description dead man's switch, cancel all orders after the given timeout
3005
+ * @see https://api.docs.extended.exchange/#mass-auto-cancel-dead-man-39-s-switch
3006
+ * @param {number} timeout time in milliseconds, 0 represents cancel the timer
3007
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3008
+ * @returns {object} the api result
3009
+ */
3010
+ async cancelAllOrdersAfter(timeout, params = {}) {
3011
+ await this.loadMarkets();
3012
+ const request = {
3013
+ 'countdownTime': (timeout > 0) ? this.parseToInt(timeout / 1000) : 0,
3014
+ };
3015
+ return await this.v1PrivatePostUserDeadmanswitch(this.extend(request, params));
3016
+ }
3017
+ /**
3018
+ * @method
3019
+ * @name extended#fetchOrder
3020
+ * @description fetches information on an order made by the user
3021
+ * @see https://api.docs.extended.exchange/#get-order-by-id
3022
+ * @see https://api.docs.extended.exchange/#get-orders-by-external-id
3023
+ * @param {string} id order id assigned by Extended
3024
+ * @param {string} [symbol] unified symbol of the market the order was made in
3025
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3026
+ * @param {string} [params.clientOrderId] user-defined order id, fetches by external id
3027
+ * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
3028
+ */
3029
+ async fetchOrder(id, symbol = undefined, params = {}) {
3030
+ await this.loadMarkets();
3031
+ let market = undefined;
3032
+ if (symbol !== undefined) {
3033
+ market = this.market(symbol);
3034
+ }
3035
+ let response = undefined;
3036
+ let order = undefined;
3037
+ const clientOrderId = this.safeString2(params, 'clientOrderId', 'client_id');
3038
+ params = this.omit(params, ['clientOrderId', 'client_id']);
3039
+ if (clientOrderId !== undefined) {
3040
+ const request = {
3041
+ 'externalId': clientOrderId,
3042
+ };
3043
+ response = await this.v1PrivateGetUserOrdersExternalExternalId(this.extend(request, params));
3044
+ const data = this.safeList(response, 'data', []);
3045
+ order = this.safeDict(data, 0, {});
3046
+ }
3047
+ else {
3048
+ if (id === undefined) {
3049
+ throw new errors.ArgumentsRequired(this.id + ' fetchOrder() requires an id argument');
3050
+ }
3051
+ const request = {
3052
+ 'id': id,
3053
+ };
3054
+ response = await this.v1PrivateGetUserOrdersId(this.extend(request, params));
3055
+ order = this.safeDict(response, 'data', {});
3056
+ }
3057
+ return this.parseOrder(order, market);
3058
+ }
3059
+ /**
3060
+ * @method
3061
+ * @name extended#fetchOpenOrders
3062
+ * @description fetch all unfilled currently open orders
3063
+ * @see https://api.docs.extended.exchange/#get-open-orders
3064
+ * @param {string} [symbol] unified market symbol of the orders
3065
+ * @param {int} [since] the earliest time in ms to fetch orders for
3066
+ * @param {int} [limit] the maximum number of open order structures to retrieve
3067
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3068
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
3069
+ */
3070
+ async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
3071
+ await this.loadMarkets();
3072
+ let market = undefined;
3073
+ const request = {};
3074
+ if (symbol !== undefined) {
3075
+ market = this.market(symbol);
3076
+ request['market'] = market['id'];
3077
+ }
3078
+ const response = await this.v1PrivateGetUserOrders(this.extend(request, params));
3079
+ //
3080
+ // {
3081
+ // "status": "OK",
3082
+ // "data": [
3083
+ // {
3084
+ // "id": 1775511783722512384,
3085
+ // "accountId": 3017,
3086
+ // "externalId": "2554612759479898620327573136214120486511160383028978112799136270841501275076",
3087
+ // "market": "ETH-USD",
3088
+ // "type": "LIMIT",
3089
+ // "side": "BUY",
3090
+ // "status": "PARTIALLY_FILLED",
3091
+ // "price": "3300",
3092
+ // "averagePrice": "3297.00",
3093
+ // "qty": "0.2",
3094
+ // "filledQty": "0.1",
3095
+ // "payedFee": "0.0120000000000000",
3096
+ // "reduceOnly": false,
3097
+ // "postOnly": false,
3098
+ // "createdTime": 1701563440000,
3099
+ // "updatedTime": 1701563440000,
3100
+ // "timeInForce": "IOC",
3101
+ // "expireTime": 1712754771819
3102
+ // }
3103
+ // ]
3104
+ // }
3105
+ //
3106
+ const data = this.safeList(response, 'data', []);
3107
+ const orders = this.parseOrders(data, market, since, limit);
3108
+ return this.filterBySymbolSinceLimit(orders, symbol, since, limit);
3109
+ }
3110
+ /**
3111
+ * @method
3112
+ * @name extended#fetchOrders
3113
+ * @description fetches information on multiple orders made by the user
3114
+ * @see https://api.docs.extended.exchange/#get-orders-history
3115
+ * @param {string} [symbol] unified market symbol of the orders
3116
+ * @param {int} [since] the earliest time in ms to fetch orders for
3117
+ * @param {int} [limit] the maximum number of order structures to retrieve
3118
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3119
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
3120
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
3121
+ */
3122
+ async fetchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
3123
+ await this.loadMarkets();
3124
+ let paginate = false;
3125
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchOrders', 'paginate');
3126
+ if (paginate) {
3127
+ return await this.fetchPaginatedCallCursor('fetchOrders', symbol, since, limit, params, 'cursor', 'cursor', undefined, 100);
3128
+ }
3129
+ let market = undefined;
3130
+ const request = {};
3131
+ if (symbol !== undefined) {
3132
+ market = this.market(symbol);
3133
+ request['market'] = market['id'];
3134
+ }
3135
+ if (limit !== undefined) {
3136
+ request['limit'] = limit;
3137
+ }
3138
+ const response = await this.v1PrivateGetUserOrdersHistory(this.extend(params, request));
3139
+ //
3140
+ // {
3141
+ // "status": "OK",
3142
+ // "data": [
3143
+ // {
3144
+ // "id": 1784963886257016832,
3145
+ // "externalId": "ExtId-1",
3146
+ // "accountId": 1,
3147
+ // "market": "BTC-USD",
3148
+ // "status": "FILLED",
3149
+ // "type": "LIMIT",
3150
+ // "side": "BUY",
3151
+ // "price": "39000",
3152
+ // "averagePrice": "39000",
3153
+ // "qty": "0.2",
3154
+ // "filledQty": "0.1",
3155
+ // "payedFee": "0.0120000000000000",
3156
+ // "reduceOnly": false,
3157
+ // "postOnly": false,
3158
+ // "createdTime": 1701563440000,
3159
+ // "updatedTime": 1701563440000,
3160
+ // "timeInForce": "IOC",
3161
+ // "expireTime": 1706563440
3162
+ // }
3163
+ // ],
3164
+ // "pagination": {
3165
+ // "cursor": 1784963886257016832,
3166
+ // "count": 1
3167
+ // }
3168
+ // }
3169
+ //
3170
+ const data = this.safeList(response, 'data', []);
3171
+ const pagination = this.safeDict(response, 'pagination', {});
3172
+ const cursor = this.safeString(pagination, 'cursor');
3173
+ const result = [];
3174
+ const dataLength = data.length;
3175
+ for (let i = 0; i < dataLength; i++) {
3176
+ let entry = data[i];
3177
+ if ((cursor !== undefined) && (i === dataLength - 1)) {
3178
+ entry = this.extend(entry, { 'cursor': cursor });
3179
+ }
3180
+ result.push(entry);
3181
+ }
3182
+ const orders = this.parseOrders(result, market, since, limit);
3183
+ return this.filterBySymbolSinceLimit(orders, symbol, since, limit);
3184
+ }
3185
+ /**
3186
+ * @method
3187
+ * @name extended#fetchClosedOrders
3188
+ * @description fetches information on multiple closed orders made by the user
3189
+ * @see https://api.docs.extended.exchange/#get-orders-history
3190
+ * @param {string} [symbol] unified market symbol of the orders
3191
+ * @param {int} [since] the earliest time in ms to fetch orders for
3192
+ * @param {int} [limit] the maximum number of order structures to retrieve
3193
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3194
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
3195
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
3196
+ */
3197
+ async fetchClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
3198
+ const orders = await this.fetchOrders(symbol, since, undefined, params);
3199
+ const closedOrders = this.filterBy(orders, 'status', 'closed');
3200
+ return this.filterBySymbolSinceLimit(closedOrders, symbol, since, limit);
3201
+ }
3202
+ /**
3203
+ * @method
3204
+ * @name extended#fetchCanceledOrders
3205
+ * @description fetches information on multiple canceled orders made by the user
3206
+ * @see https://api.docs.extended.exchange/#get-orders-history
3207
+ * @param {string} [symbol] unified market symbol of the orders
3208
+ * @param {int} [since] the earliest time in ms to fetch orders for
3209
+ * @param {int} [limit] the maximum number of order structures to retrieve
3210
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3211
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
3212
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
3213
+ */
3214
+ async fetchCanceledOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
3215
+ const orders = await this.fetchOrders(symbol, since, undefined, params);
3216
+ const canceledOrders = this.filterBy(orders, 'status', 'canceled');
3217
+ return this.filterBySymbolSinceLimit(canceledOrders, symbol, since, limit);
3218
+ }
3219
+ parseOrderStatus(status) {
3220
+ const statuses = {
3221
+ 'NEW': 'open',
3222
+ 'PARTIALLY_FILLED': 'open',
3223
+ 'UNTRIGGERED': 'open',
3224
+ 'TRIGGERED': 'open',
3225
+ 'FILLED': 'closed',
3226
+ 'CANCELLED': 'canceled',
3227
+ 'REJECTED': 'rejected',
3228
+ 'EXPIRED': 'expired',
3229
+ };
3230
+ return this.safeString(statuses, status, status);
3231
+ }
3232
+ parseOrder(order, market = undefined) {
3233
+ //
3234
+ // {
3235
+ // "id": 1784963886257016832,
3236
+ // "externalId": "ExtId-1",
3237
+ // "accountId": 1,
3238
+ // "market": "BTC-USD",
3239
+ // "status": "FILLED",
3240
+ // "type": "LIMIT",
3241
+ // "side": "BUY",
3242
+ // "price": "39000",
3243
+ // "averagePrice": "39000",
3244
+ // "qty": "0.2",
3245
+ // "filledQty": "0.1",
3246
+ // "payedFee": "0.0120000000000000",
3247
+ // "reduceOnly": false,
3248
+ // "postOnly": false,
3249
+ // "trigger": {
3250
+ // "triggerPrice": "34000",
3251
+ // "triggerPriceType": "LAST",
3252
+ // "triggerPriceDirection": "UP",
3253
+ // "executionPriceType": "MARKET"
3254
+ // },
3255
+ // "takeProfit": {
3256
+ // "triggerPrice": "34000",
3257
+ // "triggerPriceType": "LAST",
3258
+ // "price": "35000",
3259
+ // "priceType": "MARKET"
3260
+ // },
3261
+ // "stopLoss": {
3262
+ // "triggerPrice": "34000",
3263
+ // "triggerPriceType": "LAST",
3264
+ // "price": "35000",
3265
+ // "priceType": "MARKET"
3266
+ // },
3267
+ // "createdTime": 1701563440000,
3268
+ // "updatedTime": 1701563440000,
3269
+ // "timeInForce": "IOC",
3270
+ // "expireTime": 1706563440
3271
+ // }
3272
+ //
3273
+ const marketId = this.safeString(order, 'market');
3274
+ market = this.safeMarket(marketId, market);
3275
+ const timestamp = this.safeInteger2(order, 'createdTime', 'timestamp');
3276
+ const lastUpdateTimestamp = this.safeInteger(order, 'updatedTime');
3277
+ const status = this.parseOrderStatus(this.safeString(order, 'status'));
3278
+ const side = this.safeStringLower(order, 'side');
3279
+ const type = this.safeStringLower(order, 'type');
3280
+ const amount = this.safeString(order, 'qty');
3281
+ const filled = this.safeString(order, 'filledQty');
3282
+ const feeCost = this.safeString(order, 'payedFee');
3283
+ const trigger = this.safeDict(order, 'trigger', {});
3284
+ const takeProfit = this.safeDict(order, 'takeProfit', {});
3285
+ const stopLoss = this.safeDict(order, 'stopLoss', {});
3286
+ const fee = {
3287
+ 'cost': feeCost,
3288
+ 'currency': (market === undefined) ? undefined : market['settle'],
3289
+ };
3290
+ return this.safeOrder({
3291
+ 'info': order,
3292
+ 'id': this.safeString(order, 'id'),
3293
+ 'clientOrderId': this.safeString(order, 'externalId'),
3294
+ 'timestamp': timestamp,
3295
+ 'datetime': this.iso8601(timestamp),
3296
+ 'lastTradeTimestamp': undefined,
3297
+ 'lastUpdateTimestamp': lastUpdateTimestamp,
3298
+ 'symbol': market['symbol'],
3299
+ 'type': type,
3300
+ 'timeInForce': this.safeString(order, 'timeInForce'),
3301
+ 'postOnly': this.safeBool(order, 'postOnly'),
3302
+ 'reduceOnly': this.safeBool(order, 'reduceOnly'),
3303
+ 'side': side,
3304
+ 'price': this.safeString(order, 'price'),
3305
+ 'triggerPrice': this.safeString(trigger, 'triggerPrice'),
3306
+ 'takeProfitPrice': this.safeString(takeProfit, 'triggerPrice'),
3307
+ 'stopLossPrice': this.safeString(stopLoss, 'triggerPrice'),
3308
+ 'amount': amount,
3309
+ 'cost': undefined,
3310
+ 'average': this.safeString(order, 'averagePrice'),
3311
+ 'filled': filled,
3312
+ 'remaining': undefined,
3313
+ 'status': status,
3314
+ 'fee': fee,
3315
+ 'trades': undefined,
3316
+ }, market);
3317
+ }
3318
+ getExtendedStringToFelt(value) {
3319
+ return this.convertToBigInt(this.stringToBase16(value));
3320
+ }
3321
+ getExtendedEncodeI64(value) {
3322
+ // Cairo prime offset for i64 negative encoding.
3323
+ const prime = '3618502788666131213697322783095070105623107215331596699973092056135872020481';
3324
+ const valueString = this.numberToString(value);
3325
+ if (Precise["default"].stringLt(valueString, '0')) {
3326
+ return Precise["default"].stringAdd(prime, valueString);
3327
+ }
3328
+ return value;
3329
+ }
3330
+ getExtendedDecimalToBase16(value) {
3331
+ let decimalString = '';
3332
+ if (typeof value === 'string') {
3333
+ decimalString = value;
3334
+ }
3335
+ else {
3336
+ decimalString = this.numberToString(value);
3337
+ }
3338
+ const hexChars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
3339
+ let result = '';
3340
+ while (Precise["default"].stringGt(decimalString, '0')) {
3341
+ const remainder = this.parseToInt(Precise["default"].stringMod(decimalString, '16'));
3342
+ result = hexChars[remainder] + result;
3343
+ decimalString = Precise["default"].stringDiv(decimalString, '16', 0);
3344
+ }
3345
+ if (result === '') {
3346
+ return '0';
3347
+ }
3348
+ return result;
3349
+ }
3350
+ getExtendedSignatureHex(signature) {
3351
+ if (typeof signature === 'string') {
3352
+ if (signature.indexOf('0x') === 0) {
3353
+ return signature;
3354
+ }
3355
+ return '0x' + this.getExtendedDecimalToBase16(signature);
3356
+ }
3357
+ const signatureString = this.numberToString(signature);
3358
+ if (signatureString.indexOf('0x') === 0) {
3359
+ return signatureString;
3360
+ }
3361
+ return '0x' + this.getExtendedDecimalToBase16(signatureString);
3362
+ }
3363
+ getExtendedDomainHash() {
3364
+ const domainTypeHash = this.convertToBigInt(this.extendedStarknetGetSelectorFromName('"StarknetDomain"("name":"shortstring","version":"shortstring","chainId":"shortstring","revision":"shortstring")'));
3365
+ const isTestnet = this.urls['api']['rest'].indexOf('sepolia') >= 0;
3366
+ const defaultChainId = isTestnet ? 'SN_SEPOLIA' : 'SN_MAIN';
3367
+ const chainId = this.safeString(this.options, 'chainId', defaultChainId);
3368
+ return this.convertToBigInt(this.extendedStarknetComputePoseidonHashOnElements([
3369
+ domainTypeHash,
3370
+ this.getExtendedStringToFelt('Perpetuals'),
3371
+ this.getExtendedStringToFelt('v0'),
3372
+ this.getExtendedStringToFelt(chainId),
3373
+ this.convertToBigInt('1'),
3374
+ ]));
3375
+ }
3376
+ getExtendedOrderMsgHash(settlement) {
3377
+ const orderTypeHash = this.convertToBigInt(this.extendedStarknetGetSelectorFromName('"Order"("position_id":"felt","base_asset_id":"AssetId","base_amount":"i64","quote_asset_id":"AssetId","quote_amount":"i64","fee_asset_id":"AssetId","fee_amount":"u64","expiration":"Timestamp","salt":"felt")"PositionId"("value":"u32")"AssetId"("value":"felt")"Timestamp"("seconds":"u64")'));
3378
+ const domainHash = this.getExtendedDomainHash();
3379
+ // Order fields
3380
+ const positionId = this.convertToBigInt(this.safeString(settlement, 'collateralPosition'));
3381
+ const baseAssetId = this.safeString(settlement, 'baseAssetId');
3382
+ const baseAmount = this.convertToBigInt(this.safeString(settlement, 'baseAmount'));
3383
+ const quoteAssetId = this.safeString(settlement, 'quoteAssetId');
3384
+ const quoteAmount = this.convertToBigInt(this.safeString(settlement, 'quoteAmount'));
3385
+ const feeAssetId = this.safeString(settlement, 'feeAssetId');
3386
+ const feeAmount = this.convertToBigInt(this.safeString(settlement, 'feeAmount'));
3387
+ const expiration = this.convertToBigInt(this.safeString2(settlement, 'expiration', 'expirationTimestamp'));
3388
+ const salt = this.convertToBigInt(this.safeString2(settlement, 'salt', 'nonce'));
3389
+ const starkKey = this.convertToBigInt(this.safeString(settlement, 'starkKey'));
3390
+ // Order struct hash
3391
+ const orderHash = this.convertToBigInt(this.extendedStarknetComputePoseidonHashOnElements([
3392
+ orderTypeHash,
3393
+ positionId,
3394
+ this.convertToBigInt(baseAssetId),
3395
+ this.getExtendedEncodeI64(baseAmount),
3396
+ this.convertToBigInt(quoteAssetId),
3397
+ this.getExtendedEncodeI64(quoteAmount),
3398
+ this.convertToBigInt(feeAssetId),
3399
+ feeAmount,
3400
+ expiration,
3401
+ salt,
3402
+ ]));
3403
+ // SNIP-12 final message hash: poseidon('StarkNet Message', domainHash, starkKey, orderHash)
3404
+ return this.extendedStarknetComputePoseidonHashOnElements([
3405
+ this.getExtendedStringToFelt('StarkNet Message'),
3406
+ domainHash,
3407
+ starkKey,
3408
+ orderHash,
3409
+ ]);
3410
+ }
3411
+ getExtendedWithdrawalMsgHash(settlement, starkKey) {
3412
+ const withdrawalTypeHash = this.convertToBigInt(this.extendedStarknetGetSelectorFromName('"Withdrawal"("recipient":"felt","position_id":"PositionId","collateral_id":"AssetId","amount":"u64","expiration":"Timestamp","salt":"felt")"PositionId"("value":"u32")"AssetId"("value":"felt")"Timestamp"("seconds":"u64")'));
3413
+ const domainHash = this.getExtendedDomainHash();
3414
+ const expiration = this.safeDict(settlement, 'expiration', {});
3415
+ const withdrawalHash = this.convertToBigInt(this.extendedStarknetComputePoseidonHashOnElements([
3416
+ withdrawalTypeHash,
3417
+ this.convertToBigInt(this.safeString(settlement, 'recipient')),
3418
+ this.convertToBigInt(this.safeString(settlement, 'positionId')),
3419
+ this.convertToBigInt(this.safeString(settlement, 'collateralId')),
3420
+ this.convertToBigInt(this.safeString(settlement, 'amount')),
3421
+ this.convertToBigInt(this.safeString(expiration, 'seconds')),
3422
+ this.convertToBigInt(this.safeString(settlement, 'salt')),
3423
+ ]));
3424
+ return this.extendedStarknetComputePoseidonHashOnElements([
3425
+ this.getExtendedStringToFelt('StarkNet Message'),
3426
+ domainHash,
3427
+ this.convertToBigInt(starkKey),
3428
+ withdrawalHash,
3429
+ ]);
3430
+ }
3431
+ getExtendedTransferMsgHash(settlement) {
3432
+ const transferTypeHash = this.convertToBigInt(this.extendedStarknetGetSelectorFromName('"Transfer"("sender_position_id":"PositionId","receiver_position_id":"PositionId","asset_id":"AssetId","amount":"u64","expiration":"Timestamp","salt":"felt")"PositionId"("value":"u32")"AssetId"("value":"felt")"Timestamp"("seconds":"u64")'));
3433
+ const domainHash = this.getExtendedDomainHash();
3434
+ const senderPublicKey = this.convertToBigInt(this.safeString(settlement, 'senderPublicKey'));
3435
+ const transferHash = this.convertToBigInt(this.extendedStarknetComputePoseidonHashOnElements([
3436
+ transferTypeHash,
3437
+ this.convertToBigInt(this.safeString(settlement, 'senderPositionId')),
3438
+ this.convertToBigInt(this.safeString(settlement, 'receiverPositionId')),
3439
+ this.convertToBigInt(this.safeString(settlement, 'assetId')),
3440
+ this.convertToBigInt(this.safeString(settlement, 'amount')),
3441
+ this.convertToBigInt(this.safeString(settlement, 'expirationTimestamp')),
3442
+ this.convertToBigInt(this.safeString(settlement, 'nonce')),
3443
+ ]));
3444
+ return this.extendedStarknetComputePoseidonHashOnElements([
3445
+ this.getExtendedStringToFelt('StarkNet Message'),
3446
+ domainHash,
3447
+ senderPublicKey,
3448
+ transferHash,
3449
+ ]);
3450
+ }
3451
+ handleErrors(httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
3452
+ if (!response) {
3453
+ return undefined; // fallback to default error handler
3454
+ }
3455
+ //
3456
+ // {"status":"ERROR","error":{"code":1140,"message":"New order cost exceeds available balance","debugInfo":"Order cost 2.000000 exceeds available for trade 0\nOrder price = 200, mark price = 95.2147597125 estimated market price = 94.81"}}
3457
+ //
3458
+ const status = this.safeStringLower(response, 'status');
3459
+ if (status === 'error') {
3460
+ const error = this.safeDict(response, 'error');
3461
+ const errorCode = this.safeString(error, 'code');
3462
+ const feedback = this.id + ' ' + this.json(response);
3463
+ this.throwBroadlyMatchedException(this.exceptions['broad'], body, feedback);
3464
+ this.throwExactlyMatchedException(this.exceptions['exact'], errorCode, feedback);
3465
+ throw new errors.ExchangeError(feedback);
3466
+ }
3467
+ return undefined;
3468
+ }
3469
+ sign(path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
3470
+ const version = this.safeString(api, 0);
3471
+ const accessibility = this.safeString(api, 1);
3472
+ const endpoint = '/' + this.implodeParams(path, params);
3473
+ const query = this.omit(params, this.extractParams(path));
3474
+ const queryPost = (path === 'user/deadmanswitch');
3475
+ let url = this.implodeHostname(this.urls['api']['rest']);
3476
+ if (accessibility === 'private') {
3477
+ // this.checkRequiredCredentials ();
3478
+ if (this.apiKey === undefined) {
3479
+ throw new errors.AuthenticationError(this.id + ' sign() requires an apiKey for private endpoints');
3480
+ }
3481
+ headers = {
3482
+ 'X-Api-Key': this.apiKey,
3483
+ };
3484
+ if (((method === 'POST') || (method === 'PATCH')) && !queryPost) {
3485
+ body = this.json(query);
3486
+ headers['Content-Type'] = 'application/json';
3487
+ }
3488
+ }
3489
+ url = url + '/api/' + version + endpoint;
3490
+ if ((method === 'GET' || method === 'DELETE' || queryPost) && Object.keys(query).length) {
3491
+ url += '?' + this.urlencodeWithArrayRepeat(query);
3492
+ }
3493
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
3494
+ }
3495
+ }
3496
+
3497
+ exports["default"] = extended;