ccxt 4.2.10 → 4.2.12

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 (383) hide show
  1. package/README.md +5 -5
  2. package/build.sh +4 -4
  3. package/dist/ccxt.browser.js +695 -282
  4. package/dist/ccxt.browser.min.js +3 -3
  5. package/dist/cjs/_virtual/agent.js +7 -0
  6. package/dist/cjs/_virtual/parse-proxy-response.js +7 -0
  7. package/dist/cjs/_virtual/promisify.js +7 -0
  8. package/dist/cjs/ccxt.js +1 -1
  9. package/dist/cjs/js/ccxt.js +474 -0
  10. package/dist/cjs/js/src/abstract/ace.js +9 -0
  11. package/dist/cjs/js/src/abstract/alpaca.js +9 -0
  12. package/dist/cjs/js/src/abstract/ascendex.js +9 -0
  13. package/dist/cjs/js/src/abstract/bigone.js +9 -0
  14. package/dist/cjs/js/src/abstract/binance.js +9 -0
  15. package/dist/cjs/js/src/abstract/bingx.js +9 -0
  16. package/dist/cjs/js/src/abstract/bit2c.js +9 -0
  17. package/dist/cjs/js/src/abstract/bitbank.js +9 -0
  18. package/dist/cjs/js/src/abstract/bitbns.js +9 -0
  19. package/dist/cjs/js/src/abstract/bitfinex.js +9 -0
  20. package/dist/cjs/js/src/abstract/bitfinex2.js +9 -0
  21. package/dist/cjs/js/src/abstract/bitflyer.js +9 -0
  22. package/dist/cjs/js/src/abstract/bitforex.js +9 -0
  23. package/dist/cjs/js/src/abstract/bitget.js +9 -0
  24. package/dist/cjs/js/src/abstract/bithumb.js +9 -0
  25. package/dist/cjs/js/src/abstract/bitmart.js +9 -0
  26. package/dist/cjs/js/src/abstract/bitmex.js +9 -0
  27. package/dist/cjs/js/src/abstract/bitopro.js +9 -0
  28. package/dist/cjs/js/src/abstract/bitpanda.js +9 -0
  29. package/dist/cjs/js/src/abstract/bitrue.js +9 -0
  30. package/dist/cjs/js/src/abstract/bitso.js +9 -0
  31. package/dist/cjs/js/src/abstract/bitstamp.js +9 -0
  32. package/dist/cjs/js/src/abstract/bitteam.js +9 -0
  33. package/dist/cjs/js/src/abstract/bitvavo.js +9 -0
  34. package/dist/cjs/js/src/abstract/bl3p.js +9 -0
  35. package/dist/cjs/js/src/abstract/blockchaincom.js +9 -0
  36. package/dist/cjs/js/src/abstract/btcalpha.js +9 -0
  37. package/dist/cjs/js/src/abstract/btcbox.js +9 -0
  38. package/dist/cjs/js/src/abstract/btcmarkets.js +9 -0
  39. package/dist/cjs/js/src/abstract/btcturk.js +9 -0
  40. package/dist/cjs/js/src/abstract/bybit.js +9 -0
  41. package/dist/cjs/js/src/abstract/cex.js +9 -0
  42. package/dist/cjs/js/src/abstract/coinbase.js +9 -0
  43. package/dist/cjs/js/src/abstract/coinbasepro.js +9 -0
  44. package/dist/cjs/js/src/abstract/coincheck.js +9 -0
  45. package/dist/cjs/js/src/abstract/coinex.js +9 -0
  46. package/dist/cjs/js/src/abstract/coinlist.js +9 -0
  47. package/dist/cjs/js/src/abstract/coinmate.js +9 -0
  48. package/dist/cjs/js/src/abstract/coinone.js +9 -0
  49. package/dist/cjs/js/src/abstract/coinsph.js +9 -0
  50. package/dist/cjs/js/src/abstract/coinspot.js +9 -0
  51. package/dist/cjs/js/src/abstract/cryptocom.js +9 -0
  52. package/dist/cjs/js/src/abstract/currencycom.js +9 -0
  53. package/dist/cjs/js/src/abstract/delta.js +9 -0
  54. package/dist/cjs/js/src/abstract/deribit.js +9 -0
  55. package/dist/cjs/js/src/abstract/digifinex.js +9 -0
  56. package/dist/cjs/js/src/abstract/exmo.js +9 -0
  57. package/dist/cjs/js/src/abstract/gate.js +9 -0
  58. package/dist/cjs/js/src/abstract/gemini.js +9 -0
  59. package/dist/cjs/js/src/abstract/hitbtc.js +9 -0
  60. package/dist/cjs/js/src/abstract/hollaex.js +9 -0
  61. package/dist/cjs/js/src/abstract/htx.js +9 -0
  62. package/dist/cjs/js/src/abstract/huobijp.js +9 -0
  63. package/dist/cjs/js/src/abstract/idex.js +9 -0
  64. package/dist/cjs/js/src/abstract/independentreserve.js +9 -0
  65. package/dist/cjs/js/src/abstract/indodax.js +9 -0
  66. package/dist/cjs/js/src/abstract/kraken.js +9 -0
  67. package/dist/cjs/js/src/abstract/krakenfutures.js +9 -0
  68. package/dist/cjs/js/src/abstract/kucoin.js +9 -0
  69. package/dist/cjs/js/src/abstract/kucoinfutures.js +9 -0
  70. package/dist/cjs/js/src/abstract/kuna.js +9 -0
  71. package/dist/cjs/js/src/abstract/latoken.js +9 -0
  72. package/dist/cjs/js/src/abstract/lbank.js +9 -0
  73. package/dist/cjs/js/src/abstract/luno.js +9 -0
  74. package/dist/cjs/js/src/abstract/lykke.js +9 -0
  75. package/dist/cjs/js/src/abstract/mercado.js +9 -0
  76. package/dist/cjs/js/src/abstract/mexc.js +9 -0
  77. package/dist/cjs/js/src/abstract/ndax.js +9 -0
  78. package/dist/cjs/js/src/abstract/novadax.js +9 -0
  79. package/dist/cjs/js/src/abstract/oceanex.js +9 -0
  80. package/dist/cjs/js/src/abstract/okcoin.js +9 -0
  81. package/dist/cjs/js/src/abstract/okx.js +9 -0
  82. package/dist/cjs/js/src/abstract/p2b.js +9 -0
  83. package/dist/cjs/js/src/abstract/paymium.js +9 -0
  84. package/dist/cjs/js/src/abstract/phemex.js +9 -0
  85. package/dist/cjs/js/src/abstract/poloniex.js +9 -0
  86. package/dist/cjs/js/src/abstract/poloniexfutures.js +9 -0
  87. package/dist/cjs/js/src/abstract/probit.js +9 -0
  88. package/dist/cjs/js/src/abstract/timex.js +9 -0
  89. package/dist/cjs/js/src/abstract/tokocrypto.js +9 -0
  90. package/dist/cjs/js/src/abstract/upbit.js +9 -0
  91. package/dist/cjs/js/src/abstract/wavesexchange.js +9 -0
  92. package/dist/cjs/js/src/abstract/wazirx.js +9 -0
  93. package/dist/cjs/js/src/abstract/whitebit.js +9 -0
  94. package/dist/cjs/js/src/abstract/woo.js +9 -0
  95. package/dist/cjs/js/src/abstract/yobit.js +9 -0
  96. package/dist/cjs/js/src/abstract/zaif.js +9 -0
  97. package/dist/cjs/js/src/abstract/zonda.js +9 -0
  98. package/dist/cjs/js/src/ace.js +1058 -0
  99. package/dist/cjs/js/src/alpaca.js +1125 -0
  100. package/dist/cjs/js/src/ascendex.js +3360 -0
  101. package/dist/cjs/js/src/base/Exchange.js +5110 -0
  102. package/dist/cjs/js/src/base/Precise.js +263 -0
  103. package/dist/cjs/js/src/base/errors.js +299 -0
  104. package/dist/cjs/js/src/base/functions/crypto.js +78 -0
  105. package/dist/cjs/js/src/base/functions/encode.js +44 -0
  106. package/dist/cjs/js/src/base/functions/generic.js +193 -0
  107. package/dist/cjs/js/src/base/functions/misc.js +96 -0
  108. package/dist/cjs/js/src/base/functions/number.js +297 -0
  109. package/dist/cjs/js/src/base/functions/platform.js +28 -0
  110. package/dist/cjs/js/src/base/functions/rsa.js +34 -0
  111. package/dist/cjs/js/src/base/functions/string.js +48 -0
  112. package/dist/cjs/js/src/base/functions/throttle.js +66 -0
  113. package/dist/cjs/js/src/base/functions/time.js +187 -0
  114. package/dist/cjs/js/src/base/functions/totp.js +24 -0
  115. package/dist/cjs/js/src/base/functions/type.js +162 -0
  116. package/dist/cjs/js/src/base/functions.js +157 -0
  117. package/dist/cjs/js/src/base/ws/Cache.js +254 -0
  118. package/dist/cjs/js/src/base/ws/Client.js +299 -0
  119. package/dist/cjs/js/src/base/ws/Future.js +34 -0
  120. package/dist/cjs/js/src/base/ws/OrderBook.js +107 -0
  121. package/dist/cjs/js/src/base/ws/OrderBookSide.js +281 -0
  122. package/dist/cjs/js/src/base/ws/WsClient.js +69 -0
  123. package/dist/cjs/js/src/bequant.js +33 -0
  124. package/dist/cjs/js/src/bigone.js +2142 -0
  125. package/dist/cjs/js/src/binance.js +9729 -0
  126. package/dist/cjs/js/src/binancecoinm.js +45 -0
  127. package/dist/cjs/js/src/binanceus.js +84 -0
  128. package/dist/cjs/js/src/binanceusdm.js +58 -0
  129. package/dist/cjs/js/src/bingx.js +3737 -0
  130. package/dist/cjs/js/src/bit2c.js +916 -0
  131. package/dist/cjs/js/src/bitbank.js +1000 -0
  132. package/dist/cjs/js/src/bitbay.js +17 -0
  133. package/dist/cjs/js/src/bitbns.js +1220 -0
  134. package/dist/cjs/js/src/bitcoincom.js +17 -0
  135. package/dist/cjs/js/src/bitfinex.js +1670 -0
  136. package/dist/cjs/js/src/bitfinex2.js +2990 -0
  137. package/dist/cjs/js/src/bitflyer.js +1045 -0
  138. package/dist/cjs/js/src/bitforex.js +852 -0
  139. package/dist/cjs/js/src/bitget.js +8284 -0
  140. package/dist/cjs/js/src/bithumb.js +1090 -0
  141. package/dist/cjs/js/src/bitmart.js +4454 -0
  142. package/dist/cjs/js/src/bitmex.js +2884 -0
  143. package/dist/cjs/js/src/bitopro.js +1724 -0
  144. package/dist/cjs/js/src/bitpanda.js +2002 -0
  145. package/dist/cjs/js/src/bitrue.js +3253 -0
  146. package/dist/cjs/js/src/bitso.js +1753 -0
  147. package/dist/cjs/js/src/bitstamp.js +2188 -0
  148. package/dist/cjs/js/src/bitteam.js +2309 -0
  149. package/dist/cjs/js/src/bitvavo.js +1968 -0
  150. package/dist/cjs/js/src/bl3p.js +447 -0
  151. package/dist/cjs/js/src/blockchaincom.js +1160 -0
  152. package/dist/cjs/js/src/btcalpha.js +929 -0
  153. package/dist/cjs/js/src/btcbox.js +565 -0
  154. package/dist/cjs/js/src/btcmarkets.js +1237 -0
  155. package/dist/cjs/js/src/btcturk.js +929 -0
  156. package/dist/cjs/js/src/bybit.js +7646 -0
  157. package/dist/cjs/js/src/cex.js +1693 -0
  158. package/dist/cjs/js/src/coinbase.js +3274 -0
  159. package/dist/cjs/js/src/coinbasepro.js +1866 -0
  160. package/dist/cjs/js/src/coincheck.js +843 -0
  161. package/dist/cjs/js/src/coinex.js +5414 -0
  162. package/dist/cjs/js/src/coinlist.js +2329 -0
  163. package/dist/cjs/js/src/coinmate.js +989 -0
  164. package/dist/cjs/js/src/coinone.js +1185 -0
  165. package/dist/cjs/js/src/coinsph.js +1933 -0
  166. package/dist/cjs/js/src/coinspot.js +548 -0
  167. package/dist/cjs/js/src/cryptocom.js +3007 -0
  168. package/dist/cjs/js/src/currencycom.js +2015 -0
  169. package/dist/cjs/js/src/delta.js +3256 -0
  170. package/dist/cjs/js/src/deribit.js +3306 -0
  171. package/dist/cjs/js/src/digifinex.js +4307 -0
  172. package/dist/cjs/js/src/exmo.js +2645 -0
  173. package/dist/cjs/js/src/fmfwio.js +34 -0
  174. package/dist/cjs/js/src/gate.js +7054 -0
  175. package/dist/cjs/js/src/gateio.js +16 -0
  176. package/dist/cjs/js/src/gemini.js +1801 -0
  177. package/dist/cjs/js/src/hitbtc.js +3660 -0
  178. package/dist/cjs/js/src/hitbtc3.js +19 -0
  179. package/dist/cjs/js/src/hollaex.js +1882 -0
  180. package/dist/cjs/js/src/htx.js +9024 -0
  181. package/dist/cjs/js/src/huobi.js +16 -0
  182. package/dist/cjs/js/src/huobijp.js +1918 -0
  183. package/dist/cjs/js/src/idex.js +1770 -0
  184. package/dist/cjs/js/src/independentreserve.js +759 -0
  185. package/dist/cjs/js/src/indodax.js +1069 -0
  186. package/dist/cjs/js/src/kraken.js +2861 -0
  187. package/dist/cjs/js/src/krakenfutures.js +2407 -0
  188. package/dist/cjs/js/src/kucoin.js +4489 -0
  189. package/dist/cjs/js/src/kucoinfutures.js +2475 -0
  190. package/dist/cjs/js/src/kuna.js +1949 -0
  191. package/dist/cjs/js/src/latoken.js +1729 -0
  192. package/dist/cjs/js/src/lbank.js +2825 -0
  193. package/dist/cjs/js/src/luno.js +1044 -0
  194. package/dist/cjs/js/src/lykke.js +1303 -0
  195. package/dist/cjs/js/src/mercado.js +897 -0
  196. package/dist/cjs/js/src/mexc.js +5407 -0
  197. package/dist/cjs/js/src/ndax.js +2450 -0
  198. package/dist/cjs/js/src/novadax.js +1556 -0
  199. package/dist/cjs/js/src/oceanex.js +964 -0
  200. package/dist/cjs/js/src/okcoin.js +3115 -0
  201. package/dist/cjs/js/src/okx.js +7329 -0
  202. package/dist/cjs/js/src/p2b.js +1243 -0
  203. package/dist/cjs/js/src/paymium.js +597 -0
  204. package/dist/cjs/js/src/phemex.js +4715 -0
  205. package/dist/cjs/js/src/poloniex.js +2356 -0
  206. package/dist/cjs/js/src/poloniexfutures.js +1794 -0
  207. package/dist/cjs/js/src/pro/alpaca.js +714 -0
  208. package/dist/cjs/js/src/pro/ascendex.js +957 -0
  209. package/dist/cjs/js/src/pro/bequant.js +33 -0
  210. package/dist/cjs/js/src/pro/binance.js +2796 -0
  211. package/dist/cjs/js/src/pro/binancecoinm.js +23 -0
  212. package/dist/cjs/js/src/pro/binanceus.js +51 -0
  213. package/dist/cjs/js/src/pro/binanceusdm.js +32 -0
  214. package/dist/cjs/js/src/pro/bingx.js +944 -0
  215. package/dist/cjs/js/src/pro/bitcoincom.js +29 -0
  216. package/dist/cjs/js/src/pro/bitfinex.js +672 -0
  217. package/dist/cjs/js/src/pro/bitfinex2.js +1159 -0
  218. package/dist/cjs/js/src/pro/bitget.js +1733 -0
  219. package/dist/cjs/js/src/pro/bitmart.js +1486 -0
  220. package/dist/cjs/js/src/pro/bitmex.js +1576 -0
  221. package/dist/cjs/js/src/pro/bitopro.js +327 -0
  222. package/dist/cjs/js/src/pro/bitpanda.js +1341 -0
  223. package/dist/cjs/js/src/pro/bitrue.js +462 -0
  224. package/dist/cjs/js/src/pro/bitstamp.js +547 -0
  225. package/dist/cjs/js/src/pro/bitvavo.js +704 -0
  226. package/dist/cjs/js/src/pro/blockchaincom.js +794 -0
  227. package/dist/cjs/js/src/pro/bybit.js +1843 -0
  228. package/dist/cjs/js/src/pro/cex.js +1510 -0
  229. package/dist/cjs/js/src/pro/coinbase.js +561 -0
  230. package/dist/cjs/js/src/pro/coinbasepro.js +968 -0
  231. package/dist/cjs/js/src/pro/coinex.js +1095 -0
  232. package/dist/cjs/js/src/pro/cryptocom.js +1020 -0
  233. package/dist/cjs/js/src/pro/currencycom.js +563 -0
  234. package/dist/cjs/js/src/pro/deribit.js +825 -0
  235. package/dist/cjs/js/src/pro/exmo.js +658 -0
  236. package/dist/cjs/js/src/pro/gate.js +1316 -0
  237. package/dist/cjs/js/src/pro/gateio.js +16 -0
  238. package/dist/cjs/js/src/pro/gemini.js +649 -0
  239. package/dist/cjs/js/src/pro/hitbtc.js +1293 -0
  240. package/dist/cjs/js/src/pro/hollaex.js +597 -0
  241. package/dist/cjs/js/src/pro/htx.js +2383 -0
  242. package/dist/cjs/js/src/pro/huobi.js +16 -0
  243. package/dist/cjs/js/src/pro/huobijp.js +606 -0
  244. package/dist/cjs/js/src/pro/idex.js +714 -0
  245. package/dist/cjs/js/src/pro/independentreserve.js +280 -0
  246. package/dist/cjs/js/src/pro/kraken.js +1364 -0
  247. package/dist/cjs/js/src/pro/krakenfutures.js +1500 -0
  248. package/dist/cjs/js/src/pro/kucoin.js +1052 -0
  249. package/dist/cjs/js/src/pro/kucoinfutures.js +981 -0
  250. package/dist/cjs/js/src/pro/luno.js +322 -0
  251. package/dist/cjs/js/src/pro/mexc.js +1170 -0
  252. package/dist/cjs/js/src/pro/ndax.js +545 -0
  253. package/dist/cjs/js/src/pro/okcoin.js +760 -0
  254. package/dist/cjs/js/src/pro/okx.js +1558 -0
  255. package/dist/cjs/js/src/pro/phemex.js +1511 -0
  256. package/dist/cjs/js/src/pro/poloniex.js +1253 -0
  257. package/dist/cjs/js/src/pro/poloniexfutures.js +1014 -0
  258. package/dist/cjs/js/src/pro/probit.js +586 -0
  259. package/dist/cjs/js/src/pro/upbit.js +234 -0
  260. package/dist/cjs/js/src/pro/wazirx.js +776 -0
  261. package/dist/cjs/js/src/pro/whitebit.js +927 -0
  262. package/dist/cjs/js/src/pro/woo.js +769 -0
  263. package/dist/cjs/js/src/probit.js +1865 -0
  264. package/dist/cjs/js/src/static_dependencies/fflake/browser.js +401 -0
  265. package/dist/cjs/js/src/static_dependencies/jsencrypt/JSEncrypt.js +195 -0
  266. package/dist/cjs/js/src/static_dependencies/jsencrypt/JSEncryptRSAKey.js +308 -0
  267. package/dist/cjs/js/src/static_dependencies/jsencrypt/lib/asn1js/asn1.js +554 -0
  268. package/dist/cjs/js/src/static_dependencies/jsencrypt/lib/asn1js/base64.js +94 -0
  269. package/dist/cjs/js/src/static_dependencies/jsencrypt/lib/asn1js/hex.js +70 -0
  270. package/dist/cjs/js/src/static_dependencies/jsencrypt/lib/asn1js/int10.js +91 -0
  271. package/dist/cjs/js/src/static_dependencies/jsencrypt/lib/jsbn/base64.js +16 -0
  272. package/dist/cjs/js/src/static_dependencies/jsencrypt/lib/jsbn/jsbn.js +1760 -0
  273. package/dist/cjs/js/src/static_dependencies/jsencrypt/lib/jsbn/prng4.js +52 -0
  274. package/dist/cjs/js/src/static_dependencies/jsencrypt/lib/jsbn/rng.js +81 -0
  275. package/dist/cjs/js/src/static_dependencies/jsencrypt/lib/jsbn/rsa.js +376 -0
  276. package/dist/cjs/js/src/static_dependencies/jsencrypt/lib/jsbn/util.js +70 -0
  277. package/dist/cjs/js/src/static_dependencies/jsencrypt/lib/jsrsasign/asn1-1.0.js +1580 -0
  278. package/dist/cjs/js/src/static_dependencies/jsencrypt/lib/jsrsasign/yahoo.js +74 -0
  279. package/dist/cjs/js/src/static_dependencies/noble-curves/_shortw_utils.js +24 -0
  280. package/dist/cjs/js/src/static_dependencies/noble-curves/abstract/curve.js +158 -0
  281. package/dist/cjs/js/src/static_dependencies/noble-curves/abstract/edwards.js +429 -0
  282. package/dist/cjs/js/src/static_dependencies/noble-curves/abstract/hash-to-curve.js +176 -0
  283. package/dist/cjs/js/src/static_dependencies/noble-curves/abstract/modular.js +324 -0
  284. package/dist/cjs/js/src/static_dependencies/noble-curves/abstract/montgomery.js +163 -0
  285. package/dist/cjs/js/src/static_dependencies/noble-curves/abstract/utils.js +245 -0
  286. package/dist/cjs/js/src/static_dependencies/noble-curves/abstract/weierstrass.js +1018 -0
  287. package/dist/cjs/js/src/static_dependencies/noble-curves/ed25519.js +383 -0
  288. package/dist/cjs/js/src/static_dependencies/noble-curves/secp256k1.js +258 -0
  289. package/dist/cjs/js/src/static_dependencies/noble-hashes/_assert.js +53 -0
  290. package/dist/cjs/js/src/static_dependencies/noble-hashes/_sha2.js +120 -0
  291. package/dist/cjs/js/src/static_dependencies/noble-hashes/_u64.js +69 -0
  292. package/dist/cjs/js/src/static_dependencies/noble-hashes/crypto.js +7 -0
  293. package/dist/cjs/js/src/static_dependencies/noble-hashes/hmac.js +83 -0
  294. package/dist/cjs/js/src/static_dependencies/noble-hashes/md5.js +240 -0
  295. package/dist/cjs/js/src/static_dependencies/noble-hashes/sha1.js +91 -0
  296. package/dist/cjs/js/src/static_dependencies/noble-hashes/sha256.js +130 -0
  297. package/dist/cjs/js/src/static_dependencies/noble-hashes/sha3.js +214 -0
  298. package/dist/cjs/js/src/static_dependencies/noble-hashes/sha512.js +239 -0
  299. package/dist/cjs/js/src/static_dependencies/noble-hashes/utils.js +93 -0
  300. package/dist/cjs/js/src/static_dependencies/node-fetch/body.js +354 -0
  301. package/dist/cjs/js/src/static_dependencies/node-fetch/errors/abort-error.js +16 -0
  302. package/dist/cjs/js/src/static_dependencies/node-fetch/errors/base.js +20 -0
  303. package/dist/cjs/js/src/static_dependencies/node-fetch/errors/fetch-error.js +30 -0
  304. package/dist/cjs/js/src/static_dependencies/node-fetch/headers.js +239 -0
  305. package/dist/cjs/js/src/static_dependencies/node-fetch/index.js +372 -0
  306. package/dist/cjs/js/src/static_dependencies/node-fetch/request.js +273 -0
  307. package/dist/cjs/js/src/static_dependencies/node-fetch/response.js +139 -0
  308. package/dist/cjs/js/src/static_dependencies/node-fetch/utils/get-search.js +14 -0
  309. package/dist/cjs/js/src/static_dependencies/node-fetch/utils/is-redirect.js +16 -0
  310. package/dist/cjs/js/src/static_dependencies/node-fetch/utils/is.js +81 -0
  311. package/dist/cjs/js/src/static_dependencies/node-fetch/utils/referrer.js +292 -0
  312. package/dist/cjs/js/src/static_dependencies/proxies/agent-base/index.js +103 -0
  313. package/dist/cjs/js/src/static_dependencies/proxies/http-proxy-agent/index.js +140 -0
  314. package/dist/cjs/js/src/static_dependencies/proxies/https-proxy-agent/index.js +175 -0
  315. package/dist/cjs/js/src/static_dependencies/proxies/https-proxy-agent/parse-proxy-response.js +95 -0
  316. package/dist/cjs/js/src/static_dependencies/qs/index.cjs.js +7 -0
  317. package/dist/cjs/js/src/static_dependencies/scure-base/index.js +383 -0
  318. package/dist/cjs/js/src/timex.js +1562 -0
  319. package/dist/cjs/js/src/tokocrypto.js +2542 -0
  320. package/dist/cjs/js/src/upbit.js +1844 -0
  321. package/dist/cjs/js/src/wavesexchange.js +2607 -0
  322. package/dist/cjs/js/src/wazirx.js +953 -0
  323. package/dist/cjs/js/src/whitebit.js +2309 -0
  324. package/dist/cjs/js/src/woo.js +2715 -0
  325. package/dist/cjs/js/src/yobit.js +1314 -0
  326. package/dist/cjs/js/src/zaif.js +736 -0
  327. package/dist/cjs/js/src/zonda.js +1883 -0
  328. package/dist/cjs/src/base/Exchange.js +11 -0
  329. package/dist/cjs/src/bingx.js +0 -10
  330. package/dist/cjs/src/bitget.js +14 -5
  331. package/dist/cjs/src/bybit.js +1 -1
  332. package/dist/cjs/src/kucoin.js +29 -5
  333. package/js/ccxt.d.ts +1 -1
  334. package/js/ccxt.js +1 -1
  335. package/js/src/abstract/bigone.d.ts +18 -0
  336. package/js/src/abstract/binance.d.ts +2 -0
  337. package/js/src/abstract/binancecoinm.d.ts +2 -0
  338. package/js/src/abstract/binanceus.d.ts +2 -0
  339. package/js/src/abstract/binanceusdm.d.ts +2 -0
  340. package/js/src/abstract/bybit.d.ts +1 -0
  341. package/js/src/abstract/gate.d.ts +11 -0
  342. package/js/src/abstract/gateio.d.ts +11 -0
  343. package/js/src/alpaca.js +18 -18
  344. package/js/src/base/Exchange.d.ts +6 -1
  345. package/js/src/base/Exchange.js +112 -12
  346. package/js/src/bigone.d.ts +1 -2
  347. package/js/src/bigone.js +340 -145
  348. package/js/src/binance.js +15 -8
  349. package/js/src/bingx.d.ts +0 -1
  350. package/js/src/bingx.js +9 -12
  351. package/js/src/bitfinex.d.ts +2 -2
  352. package/js/src/bitfinex.js +2 -3
  353. package/js/src/bitget.js +35 -13
  354. package/js/src/bitmart.d.ts +2 -2
  355. package/js/src/bitmart.js +3 -3
  356. package/js/src/bitmex.js +1 -0
  357. package/js/src/bybit.js +3 -1
  358. package/js/src/coinlist.js +2 -3
  359. package/js/src/coinsph.js +2 -3
  360. package/js/src/deribit.js +1 -0
  361. package/js/src/gate.d.ts +4 -4
  362. package/js/src/gate.js +22 -3
  363. package/js/src/hitbtc.d.ts +4 -4
  364. package/js/src/hitbtc.js +2 -3
  365. package/js/src/htx.js +4 -7
  366. package/js/src/huobijp.js +2 -3
  367. package/js/src/kraken.js +1 -0
  368. package/js/src/kucoin.js +29 -5
  369. package/js/src/mexc.js +2 -1
  370. package/js/src/okx.js +13 -3
  371. package/js/src/pro/binance.d.ts +2 -23
  372. package/js/src/pro/binance.js +58 -22
  373. package/js/src/pro/coinbase.d.ts +2 -2
  374. package/js/src/pro/coinbase.js +4 -1
  375. package/js/src/pro/coinbasepro.d.ts +2 -2
  376. package/js/src/pro/hitbtc.d.ts +2 -2
  377. package/js/src/pro/poloniex.d.ts +2 -2
  378. package/js/src/upbit.d.ts +3 -101
  379. package/js/src/upbit.js +12 -12
  380. package/js/src/woo.js +2 -0
  381. package/package.json +11 -11
  382. package/skip-tests.json +5 -0
  383. package/tests-manager.sh +2 -2
@@ -0,0 +1,3274 @@
1
+ 'use strict';
2
+
3
+ var coinbase$1 = require('./abstract/coinbase.js');
4
+ var errors = require('./base/errors.js');
5
+ var Precise = require('./base/Precise.js');
6
+ var number = require('./base/functions/number.js');
7
+ var sha256 = require('./static_dependencies/noble-hashes/sha256.js');
8
+
9
+ // ----------------------------------------------------------------------------
10
+ // ----------------------------------------------------------------------------
11
+ /**
12
+ * @class coinbase
13
+ * @augments Exchange
14
+ */
15
+ class coinbase extends coinbase$1 {
16
+ describe() {
17
+ return this.deepExtend(super.describe(), {
18
+ 'id': 'coinbase',
19
+ 'name': 'Coinbase',
20
+ 'countries': ['US'],
21
+ 'pro': true,
22
+ 'rateLimit': 400,
23
+ 'version': 'v2',
24
+ 'userAgent': this.userAgents['chrome'],
25
+ 'headers': {
26
+ 'CB-VERSION': '2018-05-30',
27
+ },
28
+ 'has': {
29
+ 'CORS': true,
30
+ 'spot': true,
31
+ 'margin': false,
32
+ 'swap': false,
33
+ 'future': false,
34
+ 'option': false,
35
+ 'addMargin': false,
36
+ 'cancelOrder': true,
37
+ 'cancelOrders': true,
38
+ 'closeAllPositions': false,
39
+ 'closePosition': false,
40
+ 'createDepositAddress': true,
41
+ 'createLimitBuyOrder': true,
42
+ 'createLimitSellOrder': true,
43
+ 'createMarketBuyOrder': true,
44
+ 'createMarketBuyOrderWithCost': true,
45
+ 'createMarketOrderWithCost': false,
46
+ 'createMarketSellOrder': true,
47
+ 'createMarketSellOrderWithCost': false,
48
+ 'createOrder': true,
49
+ 'createPostOnlyOrder': true,
50
+ 'createReduceOnlyOrder': false,
51
+ 'createStopLimitOrder': true,
52
+ 'createStopMarketOrder': false,
53
+ 'createStopOrder': true,
54
+ 'editOrder': true,
55
+ 'fetchAccounts': true,
56
+ 'fetchBalance': true,
57
+ 'fetchBidsAsks': true,
58
+ 'fetchBorrowRateHistories': false,
59
+ 'fetchBorrowRateHistory': false,
60
+ 'fetchCanceledOrders': true,
61
+ 'fetchClosedOrders': true,
62
+ 'fetchCrossBorrowRate': false,
63
+ 'fetchCrossBorrowRates': false,
64
+ 'fetchCurrencies': true,
65
+ 'fetchDeposits': true,
66
+ 'fetchFundingHistory': false,
67
+ 'fetchFundingRate': false,
68
+ 'fetchFundingRateHistory': false,
69
+ 'fetchFundingRates': false,
70
+ 'fetchIndexOHLCV': false,
71
+ 'fetchIsolatedBorrowRate': false,
72
+ 'fetchIsolatedBorrowRates': false,
73
+ 'fetchL2OrderBook': false,
74
+ 'fetchLedger': true,
75
+ 'fetchLeverage': false,
76
+ 'fetchLeverageTiers': false,
77
+ 'fetchMarginMode': false,
78
+ 'fetchMarkets': true,
79
+ 'fetchMarkOHLCV': false,
80
+ 'fetchMyBuys': true,
81
+ 'fetchMySells': true,
82
+ 'fetchMyTrades': true,
83
+ 'fetchOHLCV': true,
84
+ 'fetchOpenInterestHistory': false,
85
+ 'fetchOpenOrders': true,
86
+ 'fetchOrder': true,
87
+ 'fetchOrderBook': true,
88
+ 'fetchOrders': true,
89
+ 'fetchPosition': false,
90
+ 'fetchPositionMode': false,
91
+ 'fetchPositions': false,
92
+ 'fetchPositionsRisk': false,
93
+ 'fetchPremiumIndexOHLCV': false,
94
+ 'fetchTicker': true,
95
+ 'fetchTickers': true,
96
+ 'fetchTime': true,
97
+ 'fetchTrades': true,
98
+ 'fetchTradingFee': false,
99
+ 'fetchTradingFees': false,
100
+ 'fetchWithdrawals': true,
101
+ 'reduceMargin': false,
102
+ 'setLeverage': false,
103
+ 'setMarginMode': false,
104
+ 'setPositionMode': false,
105
+ 'withdraw': undefined,
106
+ },
107
+ 'urls': {
108
+ 'logo': 'https://user-images.githubusercontent.com/1294454/40811661-b6eceae2-653a-11e8-829e-10bfadb078cf.jpg',
109
+ 'api': {
110
+ 'rest': 'https://api.coinbase.com',
111
+ },
112
+ 'www': 'https://www.coinbase.com',
113
+ 'doc': [
114
+ 'https://developers.coinbase.com/api/v2',
115
+ 'https://docs.cloud.coinbase.com/advanced-trade-api/docs/welcome',
116
+ ],
117
+ 'fees': [
118
+ 'https://support.coinbase.com/customer/portal/articles/2109597-buy-sell-bank-transfer-fees',
119
+ 'https://www.coinbase.com/advanced-fees',
120
+ ],
121
+ 'referral': 'https://www.coinbase.com/join/58cbe25a355148797479dbd2',
122
+ },
123
+ 'requiredCredentials': {
124
+ 'apiKey': true,
125
+ 'secret': true,
126
+ },
127
+ 'api': {
128
+ 'v2': {
129
+ 'public': {
130
+ 'get': [
131
+ 'currencies',
132
+ 'time',
133
+ 'exchange-rates',
134
+ 'users/{user_id}',
135
+ 'prices/{symbol}/buy',
136
+ 'prices/{symbol}/sell',
137
+ 'prices/{symbol}/spot',
138
+ ],
139
+ },
140
+ 'private': {
141
+ 'get': [
142
+ 'accounts',
143
+ 'accounts/{account_id}',
144
+ 'accounts/{account_id}/addresses',
145
+ 'accounts/{account_id}/addresses/{address_id}',
146
+ 'accounts/{account_id}/addresses/{address_id}/transactions',
147
+ 'accounts/{account_id}/transactions',
148
+ 'accounts/{account_id}/transactions/{transaction_id}',
149
+ 'accounts/{account_id}/buys',
150
+ 'accounts/{account_id}/buys/{buy_id}',
151
+ 'accounts/{account_id}/sells',
152
+ 'accounts/{account_id}/sells/{sell_id}',
153
+ 'accounts/{account_id}/deposits',
154
+ 'accounts/{account_id}/deposits/{deposit_id}',
155
+ 'accounts/{account_id}/withdrawals',
156
+ 'accounts/{account_id}/withdrawals/{withdrawal_id}',
157
+ 'payment-methods',
158
+ 'payment-methods/{payment_method_id}',
159
+ 'user',
160
+ 'user/auth',
161
+ ],
162
+ 'post': [
163
+ 'accounts',
164
+ 'accounts/{account_id}/primary',
165
+ 'accounts/{account_id}/addresses',
166
+ 'accounts/{account_id}/transactions',
167
+ 'accounts/{account_id}/transactions/{transaction_id}/complete',
168
+ 'accounts/{account_id}/transactions/{transaction_id}/resend',
169
+ 'accounts/{account_id}/buys',
170
+ 'accounts/{account_id}/buys/{buy_id}/commit',
171
+ 'accounts/{account_id}/sells',
172
+ 'accounts/{account_id}/sells/{sell_id}/commit',
173
+ 'accounts/{account_id}/deposits',
174
+ 'accounts/{account_id}/deposits/{deposit_id}/commit',
175
+ 'accounts/{account_id}/withdrawals',
176
+ 'accounts/{account_id}/withdrawals/{withdrawal_id}/commit',
177
+ ],
178
+ 'put': [
179
+ 'accounts/{account_id}',
180
+ 'user',
181
+ ],
182
+ 'delete': [
183
+ 'accounts/{id}',
184
+ 'accounts/{account_id}/transactions/{transaction_id}',
185
+ ],
186
+ },
187
+ },
188
+ 'v3': {
189
+ 'private': {
190
+ 'get': [
191
+ 'brokerage/accounts',
192
+ 'brokerage/accounts/{account_uuid}',
193
+ 'brokerage/orders/historical/batch',
194
+ 'brokerage/orders/historical/fills',
195
+ 'brokerage/orders/historical/{order_id}',
196
+ 'brokerage/products',
197
+ 'brokerage/products/{product_id}',
198
+ 'brokerage/products/{product_id}/candles',
199
+ 'brokerage/products/{product_id}/ticker',
200
+ 'brokerage/portfolios',
201
+ 'brokerage/portfolios/{portfolio_uuid}',
202
+ 'brokerage/transaction_summary',
203
+ 'brokerage/product_book',
204
+ 'brokerage/best_bid_ask',
205
+ 'brokerage/convert/trade/{trade_id}',
206
+ 'brokerage/time',
207
+ ],
208
+ 'post': [
209
+ 'brokerage/orders',
210
+ 'brokerage/orders/batch_cancel',
211
+ 'brokerage/orders/edit',
212
+ 'brokerage/orders/edit_preview',
213
+ 'brokerage/portfolios',
214
+ 'brokerage/portfolios/move_funds',
215
+ 'brokerage/convert/quote',
216
+ 'brokerage/convert/trade/{trade_id}',
217
+ ],
218
+ 'put': [
219
+ 'brokerage/portfolios/{portfolio_uuid}',
220
+ ],
221
+ 'delete': [
222
+ 'brokerage/portfolios/{portfolio_uuid}',
223
+ ],
224
+ },
225
+ },
226
+ },
227
+ 'fees': {
228
+ 'trading': {
229
+ 'taker': this.parseNumber('0.006'),
230
+ 'maker': this.parseNumber('0.004'),
231
+ 'tierBased': true,
232
+ 'percentage': true,
233
+ 'tiers': {
234
+ 'taker': [
235
+ [this.parseNumber('0'), this.parseNumber('0.006')],
236
+ [this.parseNumber('10000'), this.parseNumber('0.004')],
237
+ [this.parseNumber('50000'), this.parseNumber('0.0025')],
238
+ [this.parseNumber('100000'), this.parseNumber('0.002')],
239
+ [this.parseNumber('1000000'), this.parseNumber('0.0018')],
240
+ [this.parseNumber('15000000'), this.parseNumber('0.0016')],
241
+ [this.parseNumber('75000000'), this.parseNumber('0.0012')],
242
+ [this.parseNumber('250000000'), this.parseNumber('0.0008')],
243
+ [this.parseNumber('400000000'), this.parseNumber('0.0005')],
244
+ ],
245
+ 'maker': [
246
+ [this.parseNumber('0'), this.parseNumber('0.004')],
247
+ [this.parseNumber('10000'), this.parseNumber('0.0025')],
248
+ [this.parseNumber('50000'), this.parseNumber('0.0015')],
249
+ [this.parseNumber('100000'), this.parseNumber('0.001')],
250
+ [this.parseNumber('1000000'), this.parseNumber('0.0008')],
251
+ [this.parseNumber('15000000'), this.parseNumber('0.0006')],
252
+ [this.parseNumber('75000000'), this.parseNumber('0.0003')],
253
+ [this.parseNumber('250000000'), this.parseNumber('0.0')],
254
+ [this.parseNumber('400000000'), this.parseNumber('0.0')],
255
+ ],
256
+ },
257
+ },
258
+ },
259
+ 'precisionMode': number.TICK_SIZE,
260
+ 'exceptions': {
261
+ 'exact': {
262
+ 'two_factor_required': errors.AuthenticationError,
263
+ 'param_required': errors.ExchangeError,
264
+ 'validation_error': errors.ExchangeError,
265
+ 'invalid_request': errors.ExchangeError,
266
+ 'personal_details_required': errors.AuthenticationError,
267
+ 'identity_verification_required': errors.AuthenticationError,
268
+ 'jumio_verification_required': errors.AuthenticationError,
269
+ 'jumio_face_match_verification_required': errors.AuthenticationError,
270
+ 'unverified_email': errors.AuthenticationError,
271
+ 'authentication_error': errors.AuthenticationError,
272
+ 'invalid_authentication_method': errors.AuthenticationError,
273
+ 'invalid_token': errors.AuthenticationError,
274
+ 'revoked_token': errors.AuthenticationError,
275
+ 'expired_token': errors.AuthenticationError,
276
+ 'invalid_scope': errors.AuthenticationError,
277
+ 'not_found': errors.ExchangeError,
278
+ 'rate_limit_exceeded': errors.RateLimitExceeded,
279
+ 'internal_server_error': errors.ExchangeError,
280
+ 'UNSUPPORTED_ORDER_CONFIGURATION': errors.BadRequest,
281
+ 'INSUFFICIENT_FUND': errors.BadRequest,
282
+ },
283
+ 'broad': {
284
+ 'request timestamp expired': errors.InvalidNonce,
285
+ 'order with this orderID was not found': errors.OrderNotFound, // {"error":"unknown","error_details":"order with this orderID was not found","message":"order with this orderID was not found"}
286
+ },
287
+ },
288
+ 'timeframes': {
289
+ '1m': 'ONE_MINUTE',
290
+ '5m': 'FIVE_MINUTE',
291
+ '15m': 'FIFTEEN_MINUTE',
292
+ '30m': 'THIRTY_MINUTE',
293
+ '1h': 'ONE_HOUR',
294
+ '2h': 'TWO_HOUR',
295
+ '6h': 'SIX_HOUR',
296
+ '1d': 'ONE_DAY',
297
+ },
298
+ 'commonCurrencies': {
299
+ 'CGLD': 'CELO',
300
+ },
301
+ 'options': {
302
+ 'stablePairs': ['BUSD-USD', 'CBETH-ETH', 'DAI-USD', 'GUSD-USD', 'GYEN-USD', 'PAX-USD', 'PAX-USDT', 'USDC-EUR', 'USDC-GBP', 'USDT-EUR', 'USDT-GBP', 'USDT-USD', 'USDT-USDC', 'WBTC-BTC'],
303
+ 'fetchCurrencies': {
304
+ 'expires': 5000,
305
+ },
306
+ 'accounts': [
307
+ 'wallet',
308
+ 'fiat',
309
+ // 'vault',
310
+ ],
311
+ 'v3Accounts': [
312
+ 'ACCOUNT_TYPE_CRYPTO',
313
+ 'ACCOUNT_TYPE_FIAT',
314
+ ],
315
+ 'createMarketBuyOrderRequiresPrice': true,
316
+ 'advanced': true,
317
+ 'fetchMarkets': 'fetchMarketsV3',
318
+ 'fetchTicker': 'fetchTickerV3',
319
+ 'fetchTickers': 'fetchTickersV3',
320
+ 'fetchAccounts': 'fetchAccountsV3',
321
+ 'fetchBalance': 'v2PrivateGetAccounts',
322
+ 'user_native_currency': 'USD', // needed to get fees for v3
323
+ },
324
+ });
325
+ }
326
+ async fetchTime(params = {}) {
327
+ /**
328
+ * @method
329
+ * @name coinbase#fetchTime
330
+ * @description fetches the current integer timestamp in milliseconds from the exchange server
331
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-time#http-request
332
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
333
+ * @returns {int} the current integer timestamp in milliseconds from the exchange server
334
+ */
335
+ const response = await this.v2PublicGetTime(params);
336
+ //
337
+ // {
338
+ // "data": {
339
+ // "epoch": 1589295679,
340
+ // "iso": "2020-05-12T15:01:19Z"
341
+ // }
342
+ // }
343
+ //
344
+ const data = this.safeValue(response, 'data', {});
345
+ return this.safeTimestamp(data, 'epoch');
346
+ }
347
+ async fetchAccounts(params = {}) {
348
+ /**
349
+ * @method
350
+ * @name coinbase#fetchAccounts
351
+ * @description fetch all the accounts associated with a profile
352
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getaccounts
353
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-accounts#list-accounts
354
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
355
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
356
+ * @returns {object} a dictionary of [account structures]{@link https://docs.ccxt.com/#/?id=account-structure} indexed by the account type
357
+ */
358
+ const method = this.safeString(this.options, 'fetchAccounts', 'fetchAccountsV3');
359
+ if (method === 'fetchAccountsV3') {
360
+ return await this.fetchAccountsV3(params);
361
+ }
362
+ return await this.fetchAccountsV2(params);
363
+ }
364
+ async fetchAccountsV2(params = {}) {
365
+ await this.loadMarkets();
366
+ let paginate = false;
367
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchAccounts', 'paginate');
368
+ if (paginate) {
369
+ return await this.fetchPaginatedCallCursor('fetchAccounts', undefined, undefined, undefined, params, 'next_starting_after', 'starting_after', undefined, 100);
370
+ }
371
+ const request = {
372
+ 'limit': 100,
373
+ };
374
+ const response = await this.v2PrivateGetAccounts(this.extend(request, params));
375
+ //
376
+ // {
377
+ // "pagination": {
378
+ // "ending_before": null,
379
+ // "starting_after": null,
380
+ // "previous_ending_before": null,
381
+ // "next_starting_after": null,
382
+ // "limit": 244,
383
+ // "order": "desc",
384
+ // "previous_uri": null,
385
+ // "next_uri": null
386
+ // },
387
+ // "data": [
388
+ // {
389
+ // "id": "XLM",
390
+ // "name": "XLM Wallet",
391
+ // "primary": false,
392
+ // "type": "wallet",
393
+ // "currency": {
394
+ // "code": "XLM",
395
+ // "name": "Stellar Lumens",
396
+ // "color": "#000000",
397
+ // "sort_index": 127,
398
+ // "exponent": 7,
399
+ // "type": "crypto",
400
+ // "address_regex": "^G[A-Z2-7]{55}$",
401
+ // "asset_id": "13b83335-5ede-595b-821e-5bcdfa80560f",
402
+ // "destination_tag_name": "XLM Memo ID",
403
+ // "destination_tag_regex": "^[ -~]{1,28}$"
404
+ // },
405
+ // "balance": {
406
+ // "amount": "0.0000000",
407
+ // "currency": "XLM"
408
+ // },
409
+ // "created_at": null,
410
+ // "updated_at": null,
411
+ // "resource": "account",
412
+ // "resource_path": "/v2/accounts/XLM",
413
+ // "allow_deposits": true,
414
+ // "allow_withdrawals": true
415
+ // },
416
+ // ]
417
+ // }
418
+ //
419
+ const data = this.safeValue(response, 'data', []);
420
+ const pagination = this.safeValue(response, 'pagination', {});
421
+ const cursor = this.safeString(pagination, 'next_starting_after');
422
+ const accounts = this.safeValue(response, 'data', []);
423
+ const lastIndex = accounts.length - 1;
424
+ const last = this.safeValue(accounts, lastIndex);
425
+ if ((cursor !== undefined) && (cursor !== '')) {
426
+ last['next_starting_after'] = cursor;
427
+ accounts[lastIndex] = last;
428
+ }
429
+ return this.parseAccounts(data, params);
430
+ }
431
+ async fetchAccountsV3(params = {}) {
432
+ await this.loadMarkets();
433
+ let paginate = false;
434
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchAccounts', 'paginate');
435
+ if (paginate) {
436
+ return await this.fetchPaginatedCallCursor('fetchAccounts', undefined, undefined, undefined, params, 'cursor', 'cursor', undefined, 100);
437
+ }
438
+ const request = {
439
+ 'limit': 100,
440
+ };
441
+ const response = await this.v3PrivateGetBrokerageAccounts(this.extend(request, params));
442
+ //
443
+ // {
444
+ // "accounts": [
445
+ // {
446
+ // "uuid": "11111111-1111-1111-1111-111111111111",
447
+ // "name": "USDC Wallet",
448
+ // "currency": "USDC",
449
+ // "available_balance": {
450
+ // "value": "0.0000000000000000",
451
+ // "currency": "USDC"
452
+ // },
453
+ // "default": true,
454
+ // "active": true,
455
+ // "created_at": "2023-01-04T06:20:06.456Z",
456
+ // "updated_at": "2023-01-04T06:20:07.181Z",
457
+ // "deleted_at": null,
458
+ // "type": "ACCOUNT_TYPE_CRYPTO",
459
+ // "ready": false,
460
+ // "hold": {
461
+ // "value": "0.0000000000000000",
462
+ // "currency": "USDC"
463
+ // }
464
+ // },
465
+ // ...
466
+ // ],
467
+ // "has_next": false,
468
+ // "cursor": "",
469
+ // "size": 9
470
+ // }
471
+ //
472
+ const accounts = this.safeValue(response, 'accounts', []);
473
+ const lastIndex = accounts.length - 1;
474
+ const last = this.safeValue(accounts, lastIndex);
475
+ const cursor = this.safeString(response, 'cursor');
476
+ if ((cursor !== undefined) && (cursor !== '')) {
477
+ last['cursor'] = cursor;
478
+ accounts[lastIndex] = last;
479
+ }
480
+ return this.parseAccounts(accounts, params);
481
+ }
482
+ parseAccount(account) {
483
+ //
484
+ // fetchAccountsV2
485
+ //
486
+ // {
487
+ // "id": "XLM",
488
+ // "name": "XLM Wallet",
489
+ // "primary": false,
490
+ // "type": "wallet",
491
+ // "currency": {
492
+ // "code": "XLM",
493
+ // "name": "Stellar Lumens",
494
+ // "color": "#000000",
495
+ // "sort_index": 127,
496
+ // "exponent": 7,
497
+ // "type": "crypto",
498
+ // "address_regex": "^G[A-Z2-7]{55}$",
499
+ // "asset_id": "13b83335-5ede-595b-821e-5bcdfa80560f",
500
+ // "destination_tag_name": "XLM Memo ID",
501
+ // "destination_tag_regex": "^[ -~]{1,28}$"
502
+ // },
503
+ // "balance": {
504
+ // "amount": "0.0000000",
505
+ // "currency": "XLM"
506
+ // },
507
+ // "created_at": null,
508
+ // "updated_at": null,
509
+ // "resource": "account",
510
+ // "resource_path": "/v2/accounts/XLM",
511
+ // "allow_deposits": true,
512
+ // "allow_withdrawals": true
513
+ // }
514
+ //
515
+ // fetchAccountsV3
516
+ //
517
+ // {
518
+ // "uuid": "11111111-1111-1111-1111-111111111111",
519
+ // "name": "USDC Wallet",
520
+ // "currency": "USDC",
521
+ // "available_balance": {
522
+ // "value": "0.0000000000000000",
523
+ // "currency": "USDC"
524
+ // },
525
+ // "default": true,
526
+ // "active": true,
527
+ // "created_at": "2023-01-04T06:20:06.456Z",
528
+ // "updated_at": "2023-01-04T06:20:07.181Z",
529
+ // "deleted_at": null,
530
+ // "type": "ACCOUNT_TYPE_CRYPTO",
531
+ // "ready": false,
532
+ // "hold": {
533
+ // "value": "0.0000000000000000",
534
+ // "currency": "USDC"
535
+ // }
536
+ // }
537
+ //
538
+ const active = this.safeValue(account, 'active');
539
+ const currencyIdV3 = this.safeString(account, 'currency');
540
+ const currency = this.safeValue(account, 'currency', {});
541
+ const currencyId = this.safeString(currency, 'code', currencyIdV3);
542
+ const typeV3 = this.safeString(account, 'name');
543
+ const typeV2 = this.safeString(account, 'type');
544
+ const parts = typeV3.split(' ');
545
+ return {
546
+ 'id': this.safeString2(account, 'id', 'uuid'),
547
+ 'type': (active !== undefined) ? this.safeStringLower(parts, 1) : typeV2,
548
+ 'code': this.safeCurrencyCode(currencyId),
549
+ 'info': account,
550
+ };
551
+ }
552
+ async createDepositAddress(code, params = {}) {
553
+ /**
554
+ * @method
555
+ * @name coinbase#createDepositAddress
556
+ * @description create a currency deposit address
557
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-addresses#create-address
558
+ * @param {string} code unified currency code of the currency for the deposit address
559
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
560
+ * @returns {object} an [address structure]{@link https://docs.ccxt.com/#/?id=address-structure}
561
+ */
562
+ let accountId = this.safeString(params, 'account_id');
563
+ params = this.omit(params, 'account_id');
564
+ if (accountId === undefined) {
565
+ await this.loadAccounts();
566
+ for (let i = 0; i < this.accounts.length; i++) {
567
+ const account = this.accounts[i];
568
+ if (account['code'] === code && account['type'] === 'wallet') {
569
+ accountId = account['id'];
570
+ break;
571
+ }
572
+ }
573
+ }
574
+ if (accountId === undefined) {
575
+ throw new errors.ExchangeError(this.id + ' createDepositAddress() could not find the account with matching currency code, specify an `account_id` extra param');
576
+ }
577
+ const request = {
578
+ 'account_id': accountId,
579
+ };
580
+ const response = await this.v2PrivatePostAccountsAccountIdAddresses(this.extend(request, params));
581
+ //
582
+ // {
583
+ // "data": {
584
+ // "id": "05b1ebbf-9438-5dd4-b297-2ddedc98d0e4",
585
+ // "address": "coinbasebase",
586
+ // "address_info": {
587
+ // "address": "coinbasebase",
588
+ // "destination_tag": "287594668"
589
+ // },
590
+ // "name": null,
591
+ // "created_at": "2019-07-01T14:39:29Z",
592
+ // "updated_at": "2019-07-01T14:39:29Z",
593
+ // "network": "eosio",
594
+ // "uri_scheme": "eosio",
595
+ // "resource": "address",
596
+ // "resource_path": "/v2/accounts/14cfc769-e852-52f3-b831-711c104d194c/addresses/05b1ebbf-9438-5dd4-b297-2ddedc98d0e4",
597
+ // "warnings": [
598
+ // {
599
+ // "title": "Only send EOS (EOS) to this address",
600
+ // "details": "Sending any other cryptocurrency will result in permanent loss.",
601
+ // "image_url": "https://dynamic-assets.coinbase.com/deaca3d47b10ed4a91a872e9618706eec34081127762d88f2476ac8e99ada4b48525a9565cf2206d18c04053f278f693434af4d4629ca084a9d01b7a286a7e26/asset_icons/1f8489bb280fb0a0fd643c1161312ba49655040e9aaaced5f9ad3eeaf868eadc.png"
602
+ // },
603
+ // {
604
+ // "title": "Both an address and EOS memo are required to receive EOS",
605
+ // "details": "If you send funds without an EOS memo or with an incorrect EOS memo, your funds cannot be credited to your account.",
606
+ // "image_url": "https://www.coinbase.com/assets/receive-warning-2f3269d83547a7748fb39d6e0c1c393aee26669bfea6b9f12718094a1abff155.png"
607
+ // }
608
+ // ],
609
+ // "warning_title": "Only send EOS (EOS) to this address",
610
+ // "warning_details": "Sending any other cryptocurrency will result in permanent loss.",
611
+ // "destination_tag": "287594668",
612
+ // "deposit_uri": "eosio:coinbasebase?dt=287594668",
613
+ // "callback_url": null
614
+ // }
615
+ // }
616
+ //
617
+ const data = this.safeValue(response, 'data', {});
618
+ const tag = this.safeString(data, 'destination_tag');
619
+ const address = this.safeString(data, 'address');
620
+ return {
621
+ 'currency': code,
622
+ 'tag': tag,
623
+ 'address': address,
624
+ 'info': response,
625
+ };
626
+ }
627
+ async fetchMySells(symbol = undefined, since = undefined, limit = undefined, params = {}) {
628
+ /**
629
+ * @method
630
+ * @name coinbase#fetchMySells
631
+ * @ignore
632
+ * @description fetch sells
633
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-sells#list-sells
634
+ * @param {string} symbol not used by coinbase fetchMySells ()
635
+ * @param {int} [since] timestamp in ms of the earliest sell, default is undefined
636
+ * @param {int} [limit] max number of sells to return, default is undefined
637
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
638
+ * @returns {object} a [list of order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
639
+ */
640
+ // v2 did't have an endpoint for all historical trades
641
+ const request = this.prepareAccountRequest(limit, params);
642
+ await this.loadMarkets();
643
+ const query = this.omit(params, ['account_id', 'accountId']);
644
+ const sells = await this.v2PrivateGetAccountsAccountIdSells(this.extend(request, query));
645
+ return this.parseTrades(sells['data'], undefined, since, limit);
646
+ }
647
+ async fetchMyBuys(symbol = undefined, since = undefined, limit = undefined, params = {}) {
648
+ /**
649
+ * @method
650
+ * @name coinbase#fetchMyBuys
651
+ * @ignore
652
+ * @description fetch buys
653
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-buys#list-buys
654
+ * @param {string} symbol not used by coinbase fetchMyBuys ()
655
+ * @param {int} [since] timestamp in ms of the earliest buy, default is undefined
656
+ * @param {int} [limit] max number of buys to return, default is undefined
657
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
658
+ * @returns {object} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
659
+ */
660
+ // v2 did't have an endpoint for all historical trades
661
+ const request = this.prepareAccountRequest(limit, params);
662
+ await this.loadMarkets();
663
+ const query = this.omit(params, ['account_id', 'accountId']);
664
+ const buys = await this.v2PrivateGetAccountsAccountIdBuys(this.extend(request, query));
665
+ return this.parseTrades(buys['data'], undefined, since, limit);
666
+ }
667
+ async fetchTransactionsWithMethod(method, code = undefined, since = undefined, limit = undefined, params = {}) {
668
+ const request = await this.prepareAccountRequestWithCurrencyCode(code, limit, params);
669
+ await this.loadMarkets();
670
+ const query = this.omit(params, ['account_id', 'accountId']);
671
+ const response = await this[method](this.extend(request, query));
672
+ return this.parseTransactions(response['data'], undefined, since, limit);
673
+ }
674
+ async fetchWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) {
675
+ /**
676
+ * @method
677
+ * @name coinbase#fetchWithdrawals
678
+ * @description fetch all withdrawals made from an account
679
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-withdrawals#list-withdrawals
680
+ * @param {string} code unified currency code
681
+ * @param {int} [since] the earliest time in ms to fetch withdrawals for
682
+ * @param {int} [limit] the maximum number of withdrawals structures to retrieve
683
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
684
+ * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
685
+ */
686
+ // fiat only, for crypto transactions use fetchLedger
687
+ return await this.fetchTransactionsWithMethod('v2PrivateGetAccountsAccountIdWithdrawals', code, since, limit, params);
688
+ }
689
+ async fetchDeposits(code = undefined, since = undefined, limit = undefined, params = {}) {
690
+ /**
691
+ * @method
692
+ * @name coinbase#fetchDeposits
693
+ * @description fetch all deposits made to an account
694
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-deposits#list-deposits
695
+ * @param {string} code unified currency code
696
+ * @param {int} [since] the earliest time in ms to fetch deposits for
697
+ * @param {int} [limit] the maximum number of deposits structures to retrieve
698
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
699
+ * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
700
+ */
701
+ // fiat only, for crypto transactions use fetchLedger
702
+ return await this.fetchTransactionsWithMethod('v2PrivateGetAccountsAccountIdDeposits', code, since, limit, params);
703
+ }
704
+ parseTransactionStatus(status) {
705
+ const statuses = {
706
+ 'created': 'pending',
707
+ 'completed': 'ok',
708
+ 'canceled': 'canceled',
709
+ };
710
+ return this.safeString(statuses, status, status);
711
+ }
712
+ parseTransaction(transaction, currency = undefined) {
713
+ //
714
+ // fiat deposit
715
+ //
716
+ // {
717
+ // "id": "f34c19f3-b730-5e3d-9f72",
718
+ // "status": "completed",
719
+ // "payment_method": {
720
+ // "id": "a022b31d-f9c7-5043-98f2",
721
+ // "resource": "payment_method",
722
+ // "resource_path": "/v2/payment-methods/a022b31d-f9c7-5043-98f2"
723
+ // },
724
+ // "transaction": {
725
+ // "id": "04ed4113-3732-5b0c-af86-b1d2146977d0",
726
+ // "resource": "transaction",
727
+ // "resource_path": "/v2/accounts/91cd2d36-3a91-55b6-a5d4-0124cf105483/transactions/04ed4113-3732-5b0c-af86"
728
+ // },
729
+ // "user_reference": "2VTYTH",
730
+ // "created_at": "2017-02-09T07:01:18Z",
731
+ // "updated_at": "2017-02-09T07:01:26Z",
732
+ // "resource": "deposit",
733
+ // "resource_path": "/v2/accounts/91cd2d36-3a91-55b6-a5d4-0124cf105483/deposits/f34c19f3-b730-5e3d-9f72",
734
+ // "committed": true,
735
+ // "payout_at": "2017-02-12T07:01:17Z",
736
+ // "instant": false,
737
+ // "fee": { "amount": "0.00", "currency": "EUR" },
738
+ // "amount": { "amount": "114.02", "currency": "EUR" },
739
+ // "subtotal": { "amount": "114.02", "currency": "EUR" },
740
+ // "hold_until": null,
741
+ // "hold_days": 0,
742
+ // "hold_business_days": 0,
743
+ // "next_step": null
744
+ // }
745
+ //
746
+ // fiat_withdrawal
747
+ //
748
+ // {
749
+ // "id": "cfcc3b4a-eeb6-5e8c-8058",
750
+ // "status": "completed",
751
+ // "payment_method": {
752
+ // "id": "8b94cfa4-f7fd-5a12-a76a",
753
+ // "resource": "payment_method",
754
+ // "resource_path": "/v2/payment-methods/8b94cfa4-f7fd-5a12-a76a"
755
+ // },
756
+ // "transaction": {
757
+ // "id": "fcc2550b-5104-5f83-a444",
758
+ // "resource": "transaction",
759
+ // "resource_path": "/v2/accounts/91cd2d36-3a91-55b6-a5d4-0124cf105483/transactions/fcc2550b-5104-5f83-a444"
760
+ // },
761
+ // "user_reference": "MEUGK",
762
+ // "created_at": "2018-07-26T08:55:12Z",
763
+ // "updated_at": "2018-07-26T08:58:18Z",
764
+ // "resource": "withdrawal",
765
+ // "resource_path": "/v2/accounts/91cd2d36-3a91-55b6-a5d4-0124cf105483/withdrawals/cfcc3b4a-eeb6-5e8c-8058",
766
+ // "committed": true,
767
+ // "payout_at": "2018-07-31T08:55:12Z",
768
+ // "instant": false,
769
+ // "fee": { "amount": "0.15", "currency": "EUR" },
770
+ // "amount": { "amount": "13130.69", "currency": "EUR" },
771
+ // "subtotal": { "amount": "13130.84", "currency": "EUR" },
772
+ // "idem": "e549dee5-63ed-4e79-8a96",
773
+ // "next_step": null
774
+ // }
775
+ //
776
+ const subtotalObject = this.safeValue(transaction, 'subtotal', {});
777
+ const feeObject = this.safeValue(transaction, 'fee', {});
778
+ const id = this.safeString(transaction, 'id');
779
+ const timestamp = this.parse8601(this.safeValue(transaction, 'created_at'));
780
+ const updated = this.parse8601(this.safeValue(transaction, 'updated_at'));
781
+ const type = this.safeString(transaction, 'resource');
782
+ const amount = this.safeNumber(subtotalObject, 'amount');
783
+ const currencyId = this.safeString(subtotalObject, 'currency');
784
+ const code = this.safeCurrencyCode(currencyId, currency);
785
+ const feeCost = this.safeNumber(feeObject, 'amount');
786
+ const feeCurrencyId = this.safeString(feeObject, 'currency');
787
+ const feeCurrency = this.safeCurrencyCode(feeCurrencyId);
788
+ const fee = {
789
+ 'cost': feeCost,
790
+ 'currency': feeCurrency,
791
+ };
792
+ let status = this.parseTransactionStatus(this.safeString(transaction, 'status'));
793
+ if (status === undefined) {
794
+ const committed = this.safeValue(transaction, 'committed');
795
+ status = committed ? 'ok' : 'pending';
796
+ }
797
+ return {
798
+ 'info': transaction,
799
+ 'id': id,
800
+ 'txid': id,
801
+ 'timestamp': timestamp,
802
+ 'datetime': this.iso8601(timestamp),
803
+ 'network': undefined,
804
+ 'address': undefined,
805
+ 'addressTo': undefined,
806
+ 'addressFrom': undefined,
807
+ 'tag': undefined,
808
+ 'tagTo': undefined,
809
+ 'tagFrom': undefined,
810
+ 'type': type,
811
+ 'amount': amount,
812
+ 'currency': code,
813
+ 'status': status,
814
+ 'updated': updated,
815
+ 'fee': fee,
816
+ };
817
+ }
818
+ parseTrade(trade, market = undefined) {
819
+ //
820
+ // fetchMyBuys, fetchMySells
821
+ //
822
+ // {
823
+ // "id": "67e0eaec-07d7-54c4-a72c-2e92826897df",
824
+ // "status": "completed",
825
+ // "payment_method": {
826
+ // "id": "83562370-3e5c-51db-87da-752af5ab9559",
827
+ // "resource": "payment_method",
828
+ // "resource_path": "/v2/payment-methods/83562370-3e5c-51db-87da-752af5ab9559"
829
+ // },
830
+ // "transaction": {
831
+ // "id": "441b9494-b3f0-5b98-b9b0-4d82c21c252a",
832
+ // "resource": "transaction",
833
+ // "resource_path": "/v2/accounts/2bbf394c-193b-5b2a-9155-3b4732659ede/transactions/441b9494-b3f0-5b98-b9b0-4d82c21c252a"
834
+ // },
835
+ // "amount": { "amount": "1.00000000", "currency": "BTC" },
836
+ // "total": { "amount": "10.25", "currency": "USD" },
837
+ // "subtotal": { "amount": "10.10", "currency": "USD" },
838
+ // "created_at": "2015-01-31T20:49:02Z",
839
+ // "updated_at": "2015-02-11T16:54:02-08:00",
840
+ // "resource": "buy",
841
+ // "resource_path": "/v2/accounts/2bbf394c-193b-5b2a-9155-3b4732659ede/buys/67e0eaec-07d7-54c4-a72c-2e92826897df",
842
+ // "committed": true,
843
+ // "instant": false,
844
+ // "fee": { "amount": "0.15", "currency": "USD" },
845
+ // "payout_at": "2015-02-18T16:54:00-08:00"
846
+ // }
847
+ //
848
+ // fetchTrades
849
+ //
850
+ // {
851
+ // "trade_id": "10092327",
852
+ // "product_id": "BTC-USDT",
853
+ // "price": "17488.12",
854
+ // "size": "0.0000623",
855
+ // "time": "2023-01-11T00:52:37.557001Z",
856
+ // "side": "BUY",
857
+ // "bid": "",
858
+ // "ask": ""
859
+ // }
860
+ //
861
+ // fetchMyTrades
862
+ //
863
+ // {
864
+ // "entry_id": "b88b82cc89e326a2778874795102cbafd08dd979a2a7a3c69603fc4c23c2e010",
865
+ // "trade_id": "cdc39e45-bbd3-44ec-bf02-61742dfb16a1",
866
+ // "order_id": "813a53c5-3e39-47bb-863d-2faf685d22d8",
867
+ // "trade_time": "2023-01-18T01:37:38.091377090Z",
868
+ // "trade_type": "FILL",
869
+ // "price": "21220.64",
870
+ // "size": "0.0046830664333996",
871
+ // "commission": "0.0000280983986004",
872
+ // "product_id": "BTC-USDT",
873
+ // "sequence_timestamp": "2023-01-18T01:37:38.092520Z",
874
+ // "liquidity_indicator": "UNKNOWN_LIQUIDITY_INDICATOR",
875
+ // "size_in_quote": true,
876
+ // "user_id": "1111111-1111-1111-1111-111111111111",
877
+ // "side": "BUY"
878
+ // }
879
+ //
880
+ let symbol = undefined;
881
+ const totalObject = this.safeValue(trade, 'total', {});
882
+ const amountObject = this.safeValue(trade, 'amount', {});
883
+ const subtotalObject = this.safeValue(trade, 'subtotal', {});
884
+ const feeObject = this.safeValue(trade, 'fee', {});
885
+ const marketId = this.safeString(trade, 'product_id');
886
+ market = this.safeMarket(marketId, market, '-');
887
+ if (market !== undefined) {
888
+ symbol = market['symbol'];
889
+ }
890
+ else {
891
+ const baseId = this.safeString(amountObject, 'currency');
892
+ const quoteId = this.safeString(totalObject, 'currency');
893
+ if ((baseId !== undefined) && (quoteId !== undefined)) {
894
+ const base = this.safeCurrencyCode(baseId);
895
+ const quote = this.safeCurrencyCode(quoteId);
896
+ symbol = base + '/' + quote;
897
+ }
898
+ }
899
+ const sizeInQuote = this.safeValue(trade, 'size_in_quote');
900
+ const v3Price = this.safeString(trade, 'price');
901
+ let v3Cost = undefined;
902
+ let v3Amount = this.safeString(trade, 'size');
903
+ if (sizeInQuote) {
904
+ // calculate base size
905
+ v3Cost = v3Amount;
906
+ v3Amount = Precise["default"].stringDiv(v3Amount, v3Price);
907
+ }
908
+ const v3FeeCost = this.safeString(trade, 'commission');
909
+ const amountString = this.safeString(amountObject, 'amount', v3Amount);
910
+ const costString = this.safeString(subtotalObject, 'amount', v3Cost);
911
+ let priceString = undefined;
912
+ let cost = undefined;
913
+ if ((costString !== undefined) && (amountString !== undefined)) {
914
+ priceString = Precise["default"].stringDiv(costString, amountString);
915
+ }
916
+ else {
917
+ priceString = v3Price;
918
+ }
919
+ if ((priceString !== undefined) && (amountString !== undefined)) {
920
+ cost = Precise["default"].stringMul(priceString, amountString);
921
+ }
922
+ else {
923
+ cost = costString;
924
+ }
925
+ let feeCurrencyId = this.safeString(feeObject, 'currency');
926
+ const feeCost = this.safeNumber(feeObject, 'amount', this.parseNumber(v3FeeCost));
927
+ if ((feeCurrencyId === undefined) && (market !== undefined) && (feeCost !== undefined)) {
928
+ feeCurrencyId = market['quote'];
929
+ }
930
+ const datetime = this.safeStringN(trade, ['created_at', 'trade_time', 'time']);
931
+ const side = this.safeStringLower2(trade, 'resource', 'side');
932
+ const takerOrMaker = this.safeStringLower(trade, 'liquidity_indicator');
933
+ return this.safeTrade({
934
+ 'info': trade,
935
+ 'id': this.safeString2(trade, 'id', 'trade_id'),
936
+ 'order': this.safeString(trade, 'order_id'),
937
+ 'timestamp': this.parse8601(datetime),
938
+ 'datetime': datetime,
939
+ 'symbol': symbol,
940
+ 'type': undefined,
941
+ 'side': (side === 'unknown_order_side') ? undefined : side,
942
+ 'takerOrMaker': (takerOrMaker === 'unknown_liquidity_indicator') ? undefined : takerOrMaker,
943
+ 'price': priceString,
944
+ 'amount': amountString,
945
+ 'cost': cost,
946
+ 'fee': {
947
+ 'cost': feeCost,
948
+ 'currency': this.safeCurrencyCode(feeCurrencyId),
949
+ },
950
+ });
951
+ }
952
+ async fetchMarkets(params = {}) {
953
+ /**
954
+ * @method
955
+ * @name coinbase#fetchMarkets
956
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getproducts
957
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-currencies#get-fiat-currencies
958
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-exchange-rates#get-exchange-rates
959
+ * @description retrieves data on all markets for coinbase
960
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
961
+ * @returns {object[]} an array of objects representing market data
962
+ */
963
+ const method = this.safeString(this.options, 'fetchMarkets', 'fetchMarketsV3');
964
+ return await this[method](params);
965
+ }
966
+ async fetchMarketsV2(params = {}) {
967
+ const response = await this.fetchCurrenciesFromCache(params);
968
+ const currencies = this.safeValue(response, 'currencies', {});
969
+ const exchangeRates = this.safeValue(response, 'exchangeRates', {});
970
+ const data = this.safeValue(currencies, 'data', []);
971
+ const dataById = this.indexBy(data, 'id');
972
+ const rates = this.safeValue(this.safeValue(exchangeRates, 'data', {}), 'rates', {});
973
+ const baseIds = Object.keys(rates);
974
+ const result = [];
975
+ for (let i = 0; i < baseIds.length; i++) {
976
+ const baseId = baseIds[i];
977
+ const base = this.safeCurrencyCode(baseId);
978
+ const type = (baseId in dataById) ? 'fiat' : 'crypto';
979
+ // https://github.com/ccxt/ccxt/issues/6066
980
+ if (type === 'crypto') {
981
+ for (let j = 0; j < data.length; j++) {
982
+ const quoteCurrency = data[j];
983
+ const quoteId = this.safeString(quoteCurrency, 'id');
984
+ const quote = this.safeCurrencyCode(quoteId);
985
+ result.push({
986
+ 'id': baseId + '-' + quoteId,
987
+ 'symbol': base + '/' + quote,
988
+ 'base': base,
989
+ 'quote': quote,
990
+ 'settle': undefined,
991
+ 'baseId': baseId,
992
+ 'quoteId': quoteId,
993
+ 'settleId': undefined,
994
+ 'type': 'spot',
995
+ 'spot': true,
996
+ 'margin': false,
997
+ 'swap': false,
998
+ 'future': false,
999
+ 'option': false,
1000
+ 'active': undefined,
1001
+ 'contract': false,
1002
+ 'linear': undefined,
1003
+ 'inverse': undefined,
1004
+ 'contractSize': undefined,
1005
+ 'expiry': undefined,
1006
+ 'expiryDatetime': undefined,
1007
+ 'strike': undefined,
1008
+ 'optionType': undefined,
1009
+ 'precision': {
1010
+ 'amount': undefined,
1011
+ 'price': undefined,
1012
+ },
1013
+ 'limits': {
1014
+ 'leverage': {
1015
+ 'min': undefined,
1016
+ 'max': undefined,
1017
+ },
1018
+ 'amount': {
1019
+ 'min': undefined,
1020
+ 'max': undefined,
1021
+ },
1022
+ 'price': {
1023
+ 'min': undefined,
1024
+ 'max': undefined,
1025
+ },
1026
+ 'cost': {
1027
+ 'min': this.safeNumber(quoteCurrency, 'min_size'),
1028
+ 'max': undefined,
1029
+ },
1030
+ },
1031
+ 'info': quoteCurrency,
1032
+ });
1033
+ }
1034
+ }
1035
+ }
1036
+ return result;
1037
+ }
1038
+ async fetchMarketsV3(params = {}) {
1039
+ const response = await this.v3PrivateGetBrokerageProducts(params);
1040
+ //
1041
+ // [
1042
+ // {
1043
+ // "product_id": "TONE-USD",
1044
+ // "price": "0.01523",
1045
+ // "price_percentage_change_24h": "1.94109772423025",
1046
+ // "volume_24h": "19773129",
1047
+ // "volume_percentage_change_24h": "437.0170530929949",
1048
+ // "base_increment": "1",
1049
+ // "quote_increment": "0.00001",
1050
+ // "quote_min_size": "1",
1051
+ // "quote_max_size": "10000000",
1052
+ // "base_min_size": "26.7187147229469674",
1053
+ // "base_max_size": "267187147.2294696735908216",
1054
+ // "base_name": "TE-FOOD",
1055
+ // "quote_name": "US Dollar",
1056
+ // "watched": false,
1057
+ // "is_disabled": false,
1058
+ // "new": false,
1059
+ // "status": "online",
1060
+ // "cancel_only": false,
1061
+ // "limit_only": false,
1062
+ // "post_only": false,
1063
+ // "trading_disabled": false,
1064
+ // "auction_mode": false,
1065
+ // "product_type": "SPOT",
1066
+ // "quote_currency_id": "USD",
1067
+ // "base_currency_id": "TONE",
1068
+ // "fcm_trading_session_details": null,
1069
+ // "mid_market_price": ""
1070
+ // },
1071
+ // ...
1072
+ // ]
1073
+ //
1074
+ const fees = await this.v3PrivateGetBrokerageTransactionSummary(params);
1075
+ //
1076
+ // {
1077
+ // "total_volume": 0,
1078
+ // "total_fees": 0,
1079
+ // "fee_tier": {
1080
+ // "pricing_tier": "",
1081
+ // "usd_from": "0",
1082
+ // "usd_to": "10000",
1083
+ // "taker_fee_rate": "0.006",
1084
+ // "maker_fee_rate": "0.004"
1085
+ // },
1086
+ // "margin_rate": null,
1087
+ // "goods_and_services_tax": null,
1088
+ // "advanced_trade_only_volume": 0,
1089
+ // "advanced_trade_only_fees": 0,
1090
+ // "coinbase_pro_volume": 0,
1091
+ // "coinbase_pro_fees": 0
1092
+ // }
1093
+ //
1094
+ const feeTier = this.safeValue(fees, 'fee_tier', {});
1095
+ const data = this.safeValue(response, 'products', []);
1096
+ const result = [];
1097
+ for (let i = 0; i < data.length; i++) {
1098
+ const market = data[i];
1099
+ const id = this.safeString(market, 'product_id');
1100
+ const baseId = this.safeString(market, 'base_currency_id');
1101
+ const quoteId = this.safeString(market, 'quote_currency_id');
1102
+ const base = this.safeCurrencyCode(baseId);
1103
+ const quote = this.safeCurrencyCode(quoteId);
1104
+ const marketType = this.safeStringLower(market, 'product_type');
1105
+ const tradingDisabled = this.safeValue(market, 'trading_disabled');
1106
+ const stablePairs = this.safeValue(this.options, 'stablePairs', []);
1107
+ result.push({
1108
+ 'id': id,
1109
+ 'symbol': base + '/' + quote,
1110
+ 'base': base,
1111
+ 'quote': quote,
1112
+ 'settle': undefined,
1113
+ 'baseId': baseId,
1114
+ 'quoteId': quoteId,
1115
+ 'settleId': undefined,
1116
+ 'type': marketType,
1117
+ 'spot': (marketType === 'spot'),
1118
+ 'margin': undefined,
1119
+ 'swap': false,
1120
+ 'future': false,
1121
+ 'option': false,
1122
+ 'active': !tradingDisabled,
1123
+ 'contract': false,
1124
+ 'linear': undefined,
1125
+ 'inverse': undefined,
1126
+ 'taker': this.inArray(id, stablePairs) ? 0.00001 : this.safeNumber(feeTier, 'taker_fee_rate'),
1127
+ 'maker': this.inArray(id, stablePairs) ? 0.0 : this.safeNumber(feeTier, 'maker_fee_rate'),
1128
+ 'contractSize': undefined,
1129
+ 'expiry': undefined,
1130
+ 'expiryDatetime': undefined,
1131
+ 'strike': undefined,
1132
+ 'optionType': undefined,
1133
+ 'precision': {
1134
+ 'amount': this.safeNumber(market, 'base_increment'),
1135
+ 'price': this.safeNumber2(market, 'price_increment', 'quote_increment'),
1136
+ },
1137
+ 'limits': {
1138
+ 'leverage': {
1139
+ 'min': undefined,
1140
+ 'max': undefined,
1141
+ },
1142
+ 'amount': {
1143
+ 'min': this.safeNumber(market, 'base_min_size'),
1144
+ 'max': this.safeNumber(market, 'base_max_size'),
1145
+ },
1146
+ 'price': {
1147
+ 'min': undefined,
1148
+ 'max': undefined,
1149
+ },
1150
+ 'cost': {
1151
+ 'min': this.safeNumber(market, 'quote_min_size'),
1152
+ 'max': this.safeNumber(market, 'quote_max_size'),
1153
+ },
1154
+ },
1155
+ 'created': undefined,
1156
+ 'info': market,
1157
+ });
1158
+ }
1159
+ return result;
1160
+ }
1161
+ async fetchCurrenciesFromCache(params = {}) {
1162
+ const options = this.safeValue(this.options, 'fetchCurrencies', {});
1163
+ const timestamp = this.safeInteger(options, 'timestamp');
1164
+ const expires = this.safeInteger(options, 'expires', 1000);
1165
+ const now = this.milliseconds();
1166
+ if ((timestamp === undefined) || ((now - timestamp) > expires)) {
1167
+ const currencies = await this.v2PublicGetCurrencies(params);
1168
+ const exchangeRates = await this.v2PublicGetExchangeRates(params);
1169
+ this.options['fetchCurrencies'] = this.extend(options, {
1170
+ 'currencies': currencies,
1171
+ 'exchangeRates': exchangeRates,
1172
+ 'timestamp': now,
1173
+ });
1174
+ }
1175
+ return this.safeValue(this.options, 'fetchCurrencies', {});
1176
+ }
1177
+ async fetchCurrencies(params = {}) {
1178
+ /**
1179
+ * @method
1180
+ * @name coinbase#fetchCurrencies
1181
+ * @description fetches all available currencies on an exchange
1182
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-currencies#get-fiat-currencies
1183
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-exchange-rates#get-exchange-rates
1184
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1185
+ * @returns {object} an associative dictionary of currencies
1186
+ */
1187
+ const response = await this.fetchCurrenciesFromCache(params);
1188
+ const currencies = this.safeValue(response, 'currencies', {});
1189
+ //
1190
+ // {
1191
+ // "data":[
1192
+ // {"id":"AED","name":"United Arab Emirates Dirham","min_size":"0.01000000"},
1193
+ // {"id":"AFN","name":"Afghan Afghani","min_size":"0.01000000"},
1194
+ // {"id":"ALL","name":"Albanian Lek","min_size":"0.01000000"},
1195
+ // {"id":"AMD","name":"Armenian Dram","min_size":"0.01000000"},
1196
+ // {"id":"ANG","name":"Netherlands Antillean Gulden","min_size":"0.01000000"},
1197
+ // ...
1198
+ // ],
1199
+ // }
1200
+ //
1201
+ const exchangeRates = this.safeValue(response, 'exchangeRates', {});
1202
+ //
1203
+ // {
1204
+ // "data":{
1205
+ // "currency":"USD",
1206
+ // "rates":{
1207
+ // "AED":"3.67",
1208
+ // "AFN":"78.21",
1209
+ // "ALL":"110.42",
1210
+ // "AMD":"474.18",
1211
+ // "ANG":"1.75",
1212
+ // ...
1213
+ // },
1214
+ // }
1215
+ // }
1216
+ //
1217
+ const data = this.safeValue(currencies, 'data', []);
1218
+ const dataById = this.indexBy(data, 'id');
1219
+ const rates = this.safeValue(this.safeValue(exchangeRates, 'data', {}), 'rates', {});
1220
+ const keys = Object.keys(rates);
1221
+ const result = {};
1222
+ for (let i = 0; i < keys.length; i++) {
1223
+ const key = keys[i];
1224
+ const type = (key in dataById) ? 'fiat' : 'crypto';
1225
+ const currency = this.safeValue(dataById, key, {});
1226
+ const id = this.safeString(currency, 'id', key);
1227
+ const name = this.safeString(currency, 'name');
1228
+ const code = this.safeCurrencyCode(id);
1229
+ result[code] = {
1230
+ 'id': id,
1231
+ 'code': code,
1232
+ 'info': currency,
1233
+ 'type': type,
1234
+ 'name': name,
1235
+ 'active': true,
1236
+ 'deposit': undefined,
1237
+ 'withdraw': undefined,
1238
+ 'fee': undefined,
1239
+ 'precision': undefined,
1240
+ 'limits': {
1241
+ 'amount': {
1242
+ 'min': this.safeNumber(currency, 'min_size'),
1243
+ 'max': undefined,
1244
+ },
1245
+ 'withdraw': {
1246
+ 'min': undefined,
1247
+ 'max': undefined,
1248
+ },
1249
+ },
1250
+ };
1251
+ }
1252
+ return result;
1253
+ }
1254
+ async fetchTickers(symbols = undefined, params = {}) {
1255
+ /**
1256
+ * @method
1257
+ * @name coinbase#fetchTickers
1258
+ * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
1259
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getproducts
1260
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-exchange-rates#get-exchange-rates
1261
+ * @param {string[]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1262
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1263
+ * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
1264
+ */
1265
+ const method = this.safeString(this.options, 'fetchTickers', 'fetchTickersV3');
1266
+ if (method === 'fetchTickersV3') {
1267
+ return await this.fetchTickersV3(symbols, params);
1268
+ }
1269
+ return await this.fetchTickersV2(symbols, params);
1270
+ }
1271
+ async fetchTickersV2(symbols = undefined, params = {}) {
1272
+ await this.loadMarkets();
1273
+ symbols = this.marketSymbols(symbols);
1274
+ const request = {
1275
+ // 'currency': 'USD',
1276
+ };
1277
+ const response = await this.v2PublicGetExchangeRates(this.extend(request, params));
1278
+ //
1279
+ // {
1280
+ // "data":{
1281
+ // "currency":"USD",
1282
+ // "rates":{
1283
+ // "AED":"3.6731",
1284
+ // "AFN":"103.163942",
1285
+ // "ALL":"106.973038",
1286
+ // }
1287
+ // }
1288
+ // }
1289
+ //
1290
+ const data = this.safeValue(response, 'data', {});
1291
+ const rates = this.safeValue(data, 'rates', {});
1292
+ const quoteId = this.safeString(data, 'currency');
1293
+ const result = {};
1294
+ const baseIds = Object.keys(rates);
1295
+ const delimiter = '-';
1296
+ for (let i = 0; i < baseIds.length; i++) {
1297
+ const baseId = baseIds[i];
1298
+ const marketId = baseId + delimiter + quoteId;
1299
+ const market = this.safeMarket(marketId, undefined, delimiter);
1300
+ const symbol = market['symbol'];
1301
+ result[symbol] = this.parseTicker(rates[baseId], market);
1302
+ }
1303
+ return this.filterByArrayTickers(result, 'symbol', symbols);
1304
+ }
1305
+ async fetchTickersV3(symbols = undefined, params = {}) {
1306
+ await this.loadMarkets();
1307
+ symbols = this.marketSymbols(symbols);
1308
+ const response = await this.v3PrivateGetBrokerageProducts(params);
1309
+ //
1310
+ // {
1311
+ // "products": [
1312
+ // {
1313
+ // "product_id": "TONE-USD",
1314
+ // "price": "0.01523",
1315
+ // "price_percentage_change_24h": "1.94109772423025",
1316
+ // "volume_24h": "19773129",
1317
+ // "volume_percentage_change_24h": "437.0170530929949",
1318
+ // "base_increment": "1",
1319
+ // "quote_increment": "0.00001",
1320
+ // "quote_min_size": "1",
1321
+ // "quote_max_size": "10000000",
1322
+ // "base_min_size": "26.7187147229469674",
1323
+ // "base_max_size": "267187147.2294696735908216",
1324
+ // "base_name": "TE-FOOD",
1325
+ // "quote_name": "US Dollar",
1326
+ // "watched": false,
1327
+ // "is_disabled": false,
1328
+ // "new": false,
1329
+ // "status": "online",
1330
+ // "cancel_only": false,
1331
+ // "limit_only": false,
1332
+ // "post_only": false,
1333
+ // "trading_disabled": false,
1334
+ // "auction_mode": false,
1335
+ // "product_type": "SPOT",
1336
+ // "quote_currency_id": "USD",
1337
+ // "base_currency_id": "TONE",
1338
+ // "fcm_trading_session_details": null,
1339
+ // "mid_market_price": ""
1340
+ // },
1341
+ // ...
1342
+ // ],
1343
+ // "num_products": 549
1344
+ // }
1345
+ //
1346
+ const data = this.safeValue(response, 'products', []);
1347
+ const result = {};
1348
+ for (let i = 0; i < data.length; i++) {
1349
+ const entry = data[i];
1350
+ const marketId = this.safeString(entry, 'product_id');
1351
+ const market = this.safeMarket(marketId, undefined, '-');
1352
+ const symbol = market['symbol'];
1353
+ result[symbol] = this.parseTicker(entry, market);
1354
+ }
1355
+ return this.filterByArrayTickers(result, 'symbol', symbols);
1356
+ }
1357
+ async fetchTicker(symbol, params = {}) {
1358
+ /**
1359
+ * @method
1360
+ * @name coinbase#fetchTicker
1361
+ * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
1362
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getmarkettrades
1363
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-prices#get-spot-price
1364
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-prices#get-buy-price
1365
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-prices#get-sell-price
1366
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
1367
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1368
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
1369
+ */
1370
+ const method = this.safeString(this.options, 'fetchTicker', 'fetchTickerV3');
1371
+ if (method === 'fetchTickerV3') {
1372
+ return await this.fetchTickerV3(symbol, params);
1373
+ }
1374
+ return await this.fetchTickerV2(symbol, params);
1375
+ }
1376
+ async fetchTickerV2(symbol, params = {}) {
1377
+ await this.loadMarkets();
1378
+ const market = this.market(symbol);
1379
+ const request = this.extend({
1380
+ 'symbol': market['id'],
1381
+ }, params);
1382
+ const spot = await this.v2PublicGetPricesSymbolSpot(request);
1383
+ //
1384
+ // {"data":{"base":"BTC","currency":"USD","amount":"48691.23"}}
1385
+ //
1386
+ const ask = await this.v2PublicGetPricesSymbolBuy(request);
1387
+ //
1388
+ // {"data":{"base":"BTC","currency":"USD","amount":"48691.23"}}
1389
+ //
1390
+ const bid = await this.v2PublicGetPricesSymbolSell(request);
1391
+ //
1392
+ // {"data":{"base":"BTC","currency":"USD","amount":"48691.23"}}
1393
+ //
1394
+ const spotData = this.safeValue(spot, 'data', {});
1395
+ const askData = this.safeValue(ask, 'data', {});
1396
+ const bidData = this.safeValue(bid, 'data', {});
1397
+ const bidAskLast = {
1398
+ 'bid': this.safeNumber(bidData, 'amount'),
1399
+ 'ask': this.safeNumber(askData, 'amount'),
1400
+ 'price': this.safeNumber(spotData, 'amount'),
1401
+ };
1402
+ return this.parseTicker(bidAskLast, market);
1403
+ }
1404
+ async fetchTickerV3(symbol, params = {}) {
1405
+ await this.loadMarkets();
1406
+ const market = this.market(symbol);
1407
+ const request = {
1408
+ 'product_id': market['id'],
1409
+ 'limit': 1,
1410
+ };
1411
+ const response = await this.v3PrivateGetBrokerageProductsProductIdTicker(this.extend(request, params));
1412
+ //
1413
+ // {
1414
+ // "trades": [
1415
+ // {
1416
+ // "trade_id": "518078013",
1417
+ // "product_id": "BTC-USD",
1418
+ // "price": "28208.1",
1419
+ // "size": "0.00659179",
1420
+ // "time": "2023-04-04T23:05:34.492746Z",
1421
+ // "side": "BUY",
1422
+ // "bid": "",
1423
+ // "ask": ""
1424
+ // }
1425
+ // ],
1426
+ // "best_bid": "28208.61",
1427
+ // "best_ask": "28208.62"
1428
+ // }
1429
+ //
1430
+ const data = this.safeValue(response, 'trades', []);
1431
+ const ticker = this.parseTicker(data[0], market);
1432
+ ticker['bid'] = this.safeNumber(response, 'best_bid');
1433
+ ticker['ask'] = this.safeNumber(response, 'best_ask');
1434
+ return ticker;
1435
+ }
1436
+ parseTicker(ticker, market = undefined) {
1437
+ //
1438
+ // fetchTickerV2
1439
+ //
1440
+ // {
1441
+ // "bid": 20713.37,
1442
+ // "ask": 20924.65,
1443
+ // "price": 20809.83
1444
+ // }
1445
+ //
1446
+ // fetchTickerV3
1447
+ //
1448
+ // {
1449
+ // "trade_id": "10209805",
1450
+ // "product_id": "BTC-USDT",
1451
+ // "price": "19381.27",
1452
+ // "size": "0.1",
1453
+ // "time": "2023-01-13T20:35:41.865970Z",
1454
+ // "side": "BUY",
1455
+ // "bid": "",
1456
+ // "ask": ""
1457
+ // }
1458
+ //
1459
+ // fetchTickersV2
1460
+ //
1461
+ // "48691.23"
1462
+ //
1463
+ // fetchTickersV3
1464
+ //
1465
+ // [
1466
+ // {
1467
+ // "product_id": "TONE-USD",
1468
+ // "price": "0.01523",
1469
+ // "price_percentage_change_24h": "1.94109772423025",
1470
+ // "volume_24h": "19773129",
1471
+ // "volume_percentage_change_24h": "437.0170530929949",
1472
+ // "base_increment": "1",
1473
+ // "quote_increment": "0.00001",
1474
+ // "quote_min_size": "1",
1475
+ // "quote_max_size": "10000000",
1476
+ // "base_min_size": "26.7187147229469674",
1477
+ // "base_max_size": "267187147.2294696735908216",
1478
+ // "base_name": "TE-FOOD",
1479
+ // "quote_name": "US Dollar",
1480
+ // "watched": false,
1481
+ // "is_disabled": false,
1482
+ // "new": false,
1483
+ // "status": "online",
1484
+ // "cancel_only": false,
1485
+ // "limit_only": false,
1486
+ // "post_only": false,
1487
+ // "trading_disabled": false,
1488
+ // "auction_mode": false,
1489
+ // "product_type": "SPOT",
1490
+ // "quote_currency_id": "USD",
1491
+ // "base_currency_id": "TONE",
1492
+ // "fcm_trading_session_details": null,
1493
+ // "mid_market_price": ""
1494
+ // },
1495
+ // ...
1496
+ // ]
1497
+ //
1498
+ // fetchBidsAsks
1499
+ //
1500
+ // {
1501
+ // "product_id": "TRAC-EUR",
1502
+ // "bids": [
1503
+ // {
1504
+ // "price": "0.2384",
1505
+ // "size": "386.1"
1506
+ // }
1507
+ // ],
1508
+ // "asks": [
1509
+ // {
1510
+ // "price": "0.2406",
1511
+ // "size": "672"
1512
+ // }
1513
+ // ],
1514
+ // "time": "2023-06-30T07:15:24.656044Z"
1515
+ // }
1516
+ //
1517
+ let bid = this.safeNumber(ticker, 'bid');
1518
+ let ask = this.safeNumber(ticker, 'ask');
1519
+ let bidVolume = undefined;
1520
+ let askVolume = undefined;
1521
+ if (('bids' in ticker)) {
1522
+ const bids = this.safeValue(ticker, 'bids', []);
1523
+ const asks = this.safeValue(ticker, 'asks', []);
1524
+ bid = this.safeNumber(bids[0], 'price');
1525
+ bidVolume = this.safeNumber(bids[0], 'size');
1526
+ ask = this.safeNumber(asks[0], 'price');
1527
+ askVolume = this.safeNumber(asks[0], 'size');
1528
+ }
1529
+ const marketId = this.safeString(ticker, 'product_id');
1530
+ const last = this.safeNumber(ticker, 'price');
1531
+ const datetime = this.safeString(ticker, 'time');
1532
+ return this.safeTicker({
1533
+ 'symbol': this.safeSymbol(marketId, market),
1534
+ 'timestamp': this.parse8601(datetime),
1535
+ 'datetime': datetime,
1536
+ 'bid': bid,
1537
+ 'ask': ask,
1538
+ 'last': last,
1539
+ 'high': undefined,
1540
+ 'low': undefined,
1541
+ 'bidVolume': bidVolume,
1542
+ 'askVolume': askVolume,
1543
+ 'vwap': undefined,
1544
+ 'open': undefined,
1545
+ 'close': last,
1546
+ 'previousClose': undefined,
1547
+ 'change': undefined,
1548
+ 'percentage': this.safeNumber(ticker, 'price_percentage_change_24h'),
1549
+ 'average': undefined,
1550
+ 'baseVolume': undefined,
1551
+ 'quoteVolume': undefined,
1552
+ 'info': ticker,
1553
+ }, market);
1554
+ }
1555
+ parseBalance(response, params = {}) {
1556
+ const balances = this.safeValue2(response, 'data', 'accounts', []);
1557
+ const accounts = this.safeValue(params, 'type', this.options['accounts']);
1558
+ const v3Accounts = this.safeValue(params, 'type', this.options['v3Accounts']);
1559
+ const result = { 'info': response };
1560
+ for (let b = 0; b < balances.length; b++) {
1561
+ const balance = balances[b];
1562
+ const type = this.safeString(balance, 'type');
1563
+ if (this.inArray(type, accounts)) {
1564
+ const value = this.safeValue(balance, 'balance');
1565
+ if (value !== undefined) {
1566
+ const currencyId = this.safeString(value, 'currency');
1567
+ const code = this.safeCurrencyCode(currencyId);
1568
+ const total = this.safeString(value, 'amount');
1569
+ const free = total;
1570
+ let account = this.safeValue(result, code);
1571
+ if (account === undefined) {
1572
+ account = this.account();
1573
+ account['free'] = free;
1574
+ account['total'] = total;
1575
+ }
1576
+ else {
1577
+ account['free'] = Precise["default"].stringAdd(account['free'], total);
1578
+ account['total'] = Precise["default"].stringAdd(account['total'], total);
1579
+ }
1580
+ result[code] = account;
1581
+ }
1582
+ }
1583
+ else if (this.inArray(type, v3Accounts)) {
1584
+ const available = this.safeValue(balance, 'available_balance');
1585
+ const hold = this.safeValue(balance, 'hold');
1586
+ if (available !== undefined && hold !== undefined) {
1587
+ const currencyId = this.safeString(available, 'currency');
1588
+ const code = this.safeCurrencyCode(currencyId);
1589
+ const used = this.safeString(hold, 'value');
1590
+ const free = this.safeString(available, 'value');
1591
+ const total = Precise["default"].stringAdd(used, free);
1592
+ let account = this.safeValue(result, code);
1593
+ if (account === undefined) {
1594
+ account = this.account();
1595
+ account['free'] = free;
1596
+ account['used'] = used;
1597
+ account['total'] = total;
1598
+ }
1599
+ else {
1600
+ account['free'] = Precise["default"].stringAdd(account['free'], free);
1601
+ account['used'] = Precise["default"].stringAdd(account['used'], used);
1602
+ account['total'] = Precise["default"].stringAdd(account['total'], total);
1603
+ }
1604
+ result[code] = account;
1605
+ }
1606
+ }
1607
+ }
1608
+ return this.safeBalance(result);
1609
+ }
1610
+ async fetchBalance(params = {}) {
1611
+ /**
1612
+ * @method
1613
+ * @name coinbase#fetchBalance
1614
+ * @description query for balance and get the amount of funds available for trading or funds locked in orders
1615
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getaccounts
1616
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-accounts#list-accounts
1617
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1618
+ * @param {boolean} [params.v3] default false, set true to use v3 api endpoint
1619
+ * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
1620
+ */
1621
+ await this.loadMarkets();
1622
+ const request = {
1623
+ 'limit': 250,
1624
+ };
1625
+ let response = undefined;
1626
+ const isV3 = this.safeValue(params, 'v3', false);
1627
+ params = this.omit(params, 'v3');
1628
+ const method = this.safeString(this.options, 'fetchBalance', 'v3PrivateGetBrokerageAccounts');
1629
+ if ((isV3) || (method === 'v3PrivateGetBrokerageAccounts')) {
1630
+ response = await this.v3PrivateGetBrokerageAccounts(this.extend(request, params));
1631
+ }
1632
+ else {
1633
+ response = await this.v2PrivateGetAccounts(this.extend(request, params));
1634
+ }
1635
+ //
1636
+ // v2PrivateGetAccounts
1637
+ // {
1638
+ // "pagination":{
1639
+ // "ending_before":null,
1640
+ // "starting_after":null,
1641
+ // "previous_ending_before":null,
1642
+ // "next_starting_after":"6b17acd6-2e68-5eb0-9f45-72d67cef578b",
1643
+ // "limit":100,
1644
+ // "order":"desc",
1645
+ // "previous_uri":null,
1646
+ // "next_uri":"/v2/accounts?limit=100\u0026starting_after=6b17acd6-2e68-5eb0-9f45-72d67cef578b"
1647
+ // },
1648
+ // "data":[
1649
+ // {
1650
+ // "id":"94ad58bc-0f15-5309-b35a-a4c86d7bad60",
1651
+ // "name":"MINA Wallet",
1652
+ // "primary":false,
1653
+ // "type":"wallet",
1654
+ // "currency":{
1655
+ // "code":"MINA",
1656
+ // "name":"Mina",
1657
+ // "color":"#EA6B48",
1658
+ // "sort_index":397,
1659
+ // "exponent":9,
1660
+ // "type":"crypto",
1661
+ // "address_regex":"^(B62)[A-Za-z0-9]{52}$",
1662
+ // "asset_id":"a4ffc575-942c-5e26-b70c-cb3befdd4229",
1663
+ // "slug":"mina"
1664
+ // },
1665
+ // "balance":{"amount":"0.000000000","currency":"MINA"},
1666
+ // "created_at":"2022-03-25T00:36:16Z",
1667
+ // "updated_at":"2022-03-25T00:36:16Z",
1668
+ // "resource":"account",
1669
+ // "resource_path":"/v2/accounts/94ad58bc-0f15-5309-b35a-a4c86d7bad60",
1670
+ // "allow_deposits":true,
1671
+ // "allow_withdrawals":true
1672
+ // },
1673
+ // ]
1674
+ // }
1675
+ //
1676
+ // v3PrivateGetBrokerageAccounts
1677
+ // {
1678
+ // "accounts": [
1679
+ // {
1680
+ // "uuid": "11111111-1111-1111-1111-111111111111",
1681
+ // "name": "USDC Wallet",
1682
+ // "currency": "USDC",
1683
+ // "available_balance": {
1684
+ // "value": "0.0000000000000000",
1685
+ // "currency": "USDC"
1686
+ // },
1687
+ // "default": true,
1688
+ // "active": true,
1689
+ // "created_at": "2023-01-04T06:20:06.456Z",
1690
+ // "updated_at": "2023-01-04T06:20:07.181Z",
1691
+ // "deleted_at": null,
1692
+ // "type": "ACCOUNT_TYPE_CRYPTO",
1693
+ // "ready": false,
1694
+ // "hold": {
1695
+ // "value": "0.0000000000000000",
1696
+ // "currency": "USDC"
1697
+ // }
1698
+ // },
1699
+ // ...
1700
+ // ],
1701
+ // "has_next": false,
1702
+ // "cursor": "",
1703
+ // "size": 9
1704
+ // }
1705
+ //
1706
+ return this.parseBalance(response, params);
1707
+ }
1708
+ async fetchLedger(code = undefined, since = undefined, limit = undefined, params = {}) {
1709
+ /**
1710
+ * @method
1711
+ * @name coinbase#fetchLedger
1712
+ * @description fetch the history of changes, actions done by the user or operations that altered balance of the user
1713
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-transactions#list-transactions
1714
+ * @param {string} code unified currency code, default is undefined
1715
+ * @param {int} [since] timestamp in ms of the earliest ledger entry, default is undefined
1716
+ * @param {int} [limit] max number of ledger entrys to return, default is undefined
1717
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1718
+ * @returns {object} a [ledger structure]{@link https://docs.ccxt.com/#/?id=ledger-structure}
1719
+ */
1720
+ await this.loadMarkets();
1721
+ let currency = undefined;
1722
+ if (code !== undefined) {
1723
+ currency = this.currency(code);
1724
+ }
1725
+ const request = await this.prepareAccountRequestWithCurrencyCode(code, limit, params);
1726
+ const query = this.omit(params, ['account_id', 'accountId']);
1727
+ // for pagination use parameter 'starting_after'
1728
+ // the value for the next page can be obtained from the result of the previous call in the 'pagination' field
1729
+ // eg: instance.last_json_response.pagination.next_starting_after
1730
+ const response = await this.v2PrivateGetAccountsAccountIdTransactions(this.extend(request, query));
1731
+ return this.parseLedger(response['data'], currency, since, limit);
1732
+ }
1733
+ parseLedgerEntryStatus(status) {
1734
+ const types = {
1735
+ 'completed': 'ok',
1736
+ };
1737
+ return this.safeString(types, status, status);
1738
+ }
1739
+ parseLedgerEntryType(type) {
1740
+ const types = {
1741
+ 'buy': 'trade',
1742
+ 'sell': 'trade',
1743
+ 'fiat_deposit': 'transaction',
1744
+ 'fiat_withdrawal': 'transaction',
1745
+ 'exchange_deposit': 'transaction',
1746
+ 'exchange_withdrawal': 'transaction',
1747
+ 'send': 'transaction',
1748
+ 'pro_deposit': 'transaction',
1749
+ 'pro_withdrawal': 'transaction', // crypto deposit (to coinbase from coinbasepro)
1750
+ };
1751
+ return this.safeString(types, type, type);
1752
+ }
1753
+ parseLedgerEntry(item, currency = undefined) {
1754
+ //
1755
+ // crypto deposit transaction
1756
+ //
1757
+ // {
1758
+ // "id": "34e4816b-4c8c-5323-a01c-35a9fa26e490",
1759
+ // "type": "send",
1760
+ // "status": "completed",
1761
+ // "amount": { amount: "28.31976528", currency: "BCH" },
1762
+ // "native_amount": { amount: "2799.65", currency: "GBP" },
1763
+ // "description": null,
1764
+ // "created_at": "2019-02-28T12:35:20Z",
1765
+ // "updated_at": "2019-02-28T12:43:24Z",
1766
+ // "resource": "transaction",
1767
+ // "resource_path": "/v2/accounts/c01d7364-edd7-5f3a-bd1d-de53d4cbb25e/transactions/34e4816b-4c8c-5323-a01c-35a9fa26e490",
1768
+ // "instant_exchange": false,
1769
+ // "network": {
1770
+ // "status": "confirmed",
1771
+ // "hash": "56222d865dae83774fccb2efbd9829cf08c75c94ce135bfe4276f3fb46d49701",
1772
+ // "transaction_url": "https://bch.btc.com/56222d865dae83774fccb2efbd9829cf08c75c94ce135bfe4276f3fb46d49701"
1773
+ // },
1774
+ // "from": { resource: "bitcoin_cash_network", currency: "BCH" },
1775
+ // "details": { title: 'Received Bitcoin Cash', subtitle: "From Bitcoin Cash address" }
1776
+ // }
1777
+ //
1778
+ // crypto withdrawal transaction
1779
+ //
1780
+ // {
1781
+ // "id": "459aad99-2c41-5698-ac71-b6b81a05196c",
1782
+ // "type": "send",
1783
+ // "status": "completed",
1784
+ // "amount": { amount: "-0.36775642", currency: "BTC" },
1785
+ // "native_amount": { amount: "-1111.65", currency: "GBP" },
1786
+ // "description": null,
1787
+ // "created_at": "2019-03-20T08:37:07Z",
1788
+ // "updated_at": "2019-03-20T08:49:33Z",
1789
+ // "resource": "transaction",
1790
+ // "resource_path": "/v2/accounts/c6afbd34-4bd0-501e-8616-4862c193cd84/transactions/459aad99-2c41-5698-ac71-b6b81a05196c",
1791
+ // "instant_exchange": false,
1792
+ // "network": {
1793
+ // "status": "confirmed",
1794
+ // "hash": "2732bbcf35c69217c47b36dce64933d103895277fe25738ffb9284092701e05b",
1795
+ // "transaction_url": "https://blockchain.info/tx/2732bbcf35c69217c47b36dce64933d103895277fe25738ffb9284092701e05b",
1796
+ // "transaction_fee": { amount: "0.00000000", currency: "BTC" },
1797
+ // "transaction_amount": { amount: "0.36775642", currency: "BTC" },
1798
+ // "confirmations": 15682
1799
+ // },
1800
+ // "to": {
1801
+ // "resource": "bitcoin_address",
1802
+ // "address": "1AHnhqbvbYx3rnZx8uC7NbFZaTe4tafFHX",
1803
+ // "currency": "BTC",
1804
+ // "address_info": { address: "1AHnhqbvbYx3rnZx8uC7NbFZaTe4tafFHX" }
1805
+ // },
1806
+ // "idem": "da0a2f14-a2af-4c5a-a37e-d4484caf582bsend",
1807
+ // "application": {
1808
+ // "id": "5756ab6e-836b-553b-8950-5e389451225d",
1809
+ // "resource": "application",
1810
+ // "resource_path": "/v2/applications/5756ab6e-836b-553b-8950-5e389451225d"
1811
+ // },
1812
+ // "details": { title: 'Sent Bitcoin', subtitle: "To Bitcoin address" }
1813
+ // }
1814
+ //
1815
+ // withdrawal transaction from coinbase to coinbasepro
1816
+ //
1817
+ // {
1818
+ // "id": "5b1b9fb8-5007-5393-b923-02903b973fdc",
1819
+ // "type": "pro_deposit",
1820
+ // "status": "completed",
1821
+ // "amount": { amount: "-0.00001111", currency: "BCH" },
1822
+ // "native_amount": { amount: "0.00", currency: "GBP" },
1823
+ // "description": null,
1824
+ // "created_at": "2019-02-28T13:31:58Z",
1825
+ // "updated_at": "2019-02-28T13:31:58Z",
1826
+ // "resource": "transaction",
1827
+ // "resource_path": "/v2/accounts/c01d7364-edd7-5f3a-bd1d-de53d4cbb25e/transactions/5b1b9fb8-5007-5393-b923-02903b973fdc",
1828
+ // "instant_exchange": false,
1829
+ // "application": {
1830
+ // "id": "5756ab6e-836b-553b-8950-5e389451225d",
1831
+ // "resource": "application",
1832
+ // "resource_path": "/v2/applications/5756ab6e-836b-553b-8950-5e389451225d"
1833
+ // },
1834
+ // "details": { title: 'Transferred Bitcoin Cash', subtitle: "To Coinbase Pro" }
1835
+ // }
1836
+ //
1837
+ // withdrawal transaction from coinbase to gdax
1838
+ //
1839
+ // {
1840
+ // "id": "badb7313-a9d3-5c07-abd0-00f8b44199b1",
1841
+ // "type": "exchange_deposit",
1842
+ // "status": "completed",
1843
+ // "amount": { amount: "-0.43704149", currency: "BCH" },
1844
+ // "native_amount": { amount: "-51.90", currency: "GBP" },
1845
+ // "description": null,
1846
+ // "created_at": "2019-03-19T10:30:40Z",
1847
+ // "updated_at": "2019-03-19T10:30:40Z",
1848
+ // "resource": "transaction",
1849
+ // "resource_path": "/v2/accounts/c01d7364-edd7-5f3a-bd1d-de53d4cbb25e/transactions/badb7313-a9d3-5c07-abd0-00f8b44199b1",
1850
+ // "instant_exchange": false,
1851
+ // "details": { title: 'Transferred Bitcoin Cash', subtitle: "To GDAX" }
1852
+ // }
1853
+ //
1854
+ // deposit transaction from gdax to coinbase
1855
+ //
1856
+ // {
1857
+ // "id": "9c4b642c-8688-58bf-8962-13cef64097de",
1858
+ // "type": "exchange_withdrawal",
1859
+ // "status": "completed",
1860
+ // "amount": { amount: "0.57729420", currency: "BTC" },
1861
+ // "native_amount": { amount: "4418.72", currency: "GBP" },
1862
+ // "description": null,
1863
+ // "created_at": "2018-02-17T11:33:33Z",
1864
+ // "updated_at": "2018-02-17T11:33:33Z",
1865
+ // "resource": "transaction",
1866
+ // "resource_path": "/v2/accounts/c6afbd34-4bd0-501e-8616-4862c193cd84/transactions/9c4b642c-8688-58bf-8962-13cef64097de",
1867
+ // "instant_exchange": false,
1868
+ // "details": { title: 'Transferred Bitcoin', subtitle: "From GDAX" }
1869
+ // }
1870
+ //
1871
+ // deposit transaction from coinbasepro to coinbase
1872
+ //
1873
+ // {
1874
+ // "id": "8d6dd0b9-3416-568a-889d-8f112fae9e81",
1875
+ // "type": "pro_withdrawal",
1876
+ // "status": "completed",
1877
+ // "amount": { amount: "0.40555386", currency: "BTC" },
1878
+ // "native_amount": { amount: "1140.27", currency: "GBP" },
1879
+ // "description": null,
1880
+ // "created_at": "2019-03-04T19:41:58Z",
1881
+ // "updated_at": "2019-03-04T19:41:58Z",
1882
+ // "resource": "transaction",
1883
+ // "resource_path": "/v2/accounts/c6afbd34-4bd0-501e-8616-4862c193cd84/transactions/8d6dd0b9-3416-568a-889d-8f112fae9e81",
1884
+ // "instant_exchange": false,
1885
+ // "application": {
1886
+ // "id": "5756ab6e-836b-553b-8950-5e389451225d",
1887
+ // "resource": "application",
1888
+ // "resource_path": "/v2/applications/5756ab6e-836b-553b-8950-5e389451225d"
1889
+ // },
1890
+ // "details": { title: 'Transferred Bitcoin', subtitle: "From Coinbase Pro" }
1891
+ // }
1892
+ //
1893
+ // sell trade
1894
+ //
1895
+ // {
1896
+ // "id": "a9409207-df64-585b-97ab-a50780d2149e",
1897
+ // "type": "sell",
1898
+ // "status": "completed",
1899
+ // "amount": { amount: "-9.09922880", currency: "BTC" },
1900
+ // "native_amount": { amount: "-7285.73", currency: "GBP" },
1901
+ // "description": null,
1902
+ // "created_at": "2017-03-27T15:38:34Z",
1903
+ // "updated_at": "2017-03-27T15:38:34Z",
1904
+ // "resource": "transaction",
1905
+ // "resource_path": "/v2/accounts/c6afbd34-4bd0-501e-8616-4862c193cd84/transactions/a9409207-df64-585b-97ab-a50780d2149e",
1906
+ // "instant_exchange": false,
1907
+ // "sell": {
1908
+ // "id": "e3550b4d-8ae6-5de3-95fe-1fb01ba83051",
1909
+ // "resource": "sell",
1910
+ // "resource_path": "/v2/accounts/c6afbd34-4bd0-501e-8616-4862c193cd84/sells/e3550b4d-8ae6-5de3-95fe-1fb01ba83051"
1911
+ // },
1912
+ // "details": {
1913
+ // "title": "Sold Bitcoin",
1914
+ // "subtitle": "Using EUR Wallet",
1915
+ // "payment_method_name": "EUR Wallet"
1916
+ // }
1917
+ // }
1918
+ //
1919
+ // buy trade
1920
+ //
1921
+ // {
1922
+ // "id": "63eeed67-9396-5912-86e9-73c4f10fe147",
1923
+ // "type": "buy",
1924
+ // "status": "completed",
1925
+ // "amount": { amount: "2.39605772", currency: "ETH" },
1926
+ // "native_amount": { amount: "98.31", currency: "GBP" },
1927
+ // "description": null,
1928
+ // "created_at": "2017-03-27T09:07:56Z",
1929
+ // "updated_at": "2017-03-27T09:07:57Z",
1930
+ // "resource": "transaction",
1931
+ // "resource_path": "/v2/accounts/8902f85d-4a69-5d74-82fe-8e390201bda7/transactions/63eeed67-9396-5912-86e9-73c4f10fe147",
1932
+ // "instant_exchange": false,
1933
+ // "buy": {
1934
+ // "id": "20b25b36-76c6-5353-aa57-b06a29a39d82",
1935
+ // "resource": "buy",
1936
+ // "resource_path": "/v2/accounts/8902f85d-4a69-5d74-82fe-8e390201bda7/buys/20b25b36-76c6-5353-aa57-b06a29a39d82"
1937
+ // },
1938
+ // "details": {
1939
+ // "title": "Bought Ethereum",
1940
+ // "subtitle": "Using EUR Wallet",
1941
+ // "payment_method_name": "EUR Wallet"
1942
+ // }
1943
+ // }
1944
+ //
1945
+ // fiat deposit transaction
1946
+ //
1947
+ // {
1948
+ // "id": "04ed4113-3732-5b0c-af86-b1d2146977d0",
1949
+ // "type": "fiat_deposit",
1950
+ // "status": "completed",
1951
+ // "amount": { amount: "114.02", currency: "EUR" },
1952
+ // "native_amount": { amount: "97.23", currency: "GBP" },
1953
+ // "description": null,
1954
+ // "created_at": "2017-02-09T07:01:21Z",
1955
+ // "updated_at": "2017-02-09T07:01:22Z",
1956
+ // "resource": "transaction",
1957
+ // "resource_path": "/v2/accounts/91cd2d36-3a91-55b6-a5d4-0124cf105483/transactions/04ed4113-3732-5b0c-af86-b1d2146977d0",
1958
+ // "instant_exchange": false,
1959
+ // "fiat_deposit": {
1960
+ // "id": "f34c19f3-b730-5e3d-9f72-96520448677a",
1961
+ // "resource": "fiat_deposit",
1962
+ // "resource_path": "/v2/accounts/91cd2d36-3a91-55b6-a5d4-0124cf105483/deposits/f34c19f3-b730-5e3d-9f72-96520448677a"
1963
+ // },
1964
+ // "details": {
1965
+ // "title": "Deposited funds",
1966
+ // "subtitle": "From SEPA Transfer (GB47 BARC 20..., reference CBADVI)",
1967
+ // "payment_method_name": "SEPA Transfer (GB47 BARC 20..., reference CBADVI)"
1968
+ // }
1969
+ // }
1970
+ //
1971
+ // fiat withdrawal transaction
1972
+ //
1973
+ // {
1974
+ // "id": "957d98e2-f80e-5e2f-a28e-02945aa93079",
1975
+ // "type": "fiat_withdrawal",
1976
+ // "status": "completed",
1977
+ // "amount": { amount: "-11000.00", currency: "EUR" },
1978
+ // "native_amount": { amount: "-9698.22", currency: "GBP" },
1979
+ // "description": null,
1980
+ // "created_at": "2017-12-06T13:19:19Z",
1981
+ // "updated_at": "2017-12-06T13:19:19Z",
1982
+ // "resource": "transaction",
1983
+ // "resource_path": "/v2/accounts/91cd2d36-3a91-55b6-a5d4-0124cf105483/transactions/957d98e2-f80e-5e2f-a28e-02945aa93079",
1984
+ // "instant_exchange": false,
1985
+ // "fiat_withdrawal": {
1986
+ // "id": "f4bf1fd9-ab3b-5de7-906d-ed3e23f7a4e7",
1987
+ // "resource": "fiat_withdrawal",
1988
+ // "resource_path": "/v2/accounts/91cd2d36-3a91-55b6-a5d4-0124cf105483/withdrawals/f4bf1fd9-ab3b-5de7-906d-ed3e23f7a4e7"
1989
+ // },
1990
+ // "details": {
1991
+ // "title": "Withdrew funds",
1992
+ // "subtitle": "To HSBC BANK PLC (GB74 MIDL...)",
1993
+ // "payment_method_name": "HSBC BANK PLC (GB74 MIDL...)"
1994
+ // }
1995
+ // }
1996
+ //
1997
+ const amountInfo = this.safeValue(item, 'amount', {});
1998
+ let amount = this.safeString(amountInfo, 'amount');
1999
+ let direction = undefined;
2000
+ if (Precise["default"].stringLt(amount, '0')) {
2001
+ direction = 'out';
2002
+ amount = Precise["default"].stringNeg(amount);
2003
+ }
2004
+ else {
2005
+ direction = 'in';
2006
+ }
2007
+ const currencyId = this.safeString(amountInfo, 'currency');
2008
+ const code = this.safeCurrencyCode(currencyId, currency);
2009
+ //
2010
+ // the address and txid do not belong to the unified ledger structure
2011
+ //
2012
+ // let address = undefined;
2013
+ // if (item['to']) {
2014
+ // address = this.safeString (item['to'], 'address');
2015
+ // }
2016
+ // let txid = undefined;
2017
+ //
2018
+ let fee = undefined;
2019
+ const networkInfo = this.safeValue(item, 'network', {});
2020
+ // txid = network['hash']; // txid does not belong to the unified ledger structure
2021
+ const feeInfo = this.safeValue(networkInfo, 'transaction_fee');
2022
+ if (feeInfo !== undefined) {
2023
+ const feeCurrencyId = this.safeString(feeInfo, 'currency');
2024
+ const feeCurrencyCode = this.safeCurrencyCode(feeCurrencyId, currency);
2025
+ const feeAmount = this.safeNumber(feeInfo, 'amount');
2026
+ fee = {
2027
+ 'cost': feeAmount,
2028
+ 'currency': feeCurrencyCode,
2029
+ };
2030
+ }
2031
+ const timestamp = this.parse8601(this.safeValue(item, 'created_at'));
2032
+ const id = this.safeString(item, 'id');
2033
+ const type = this.parseLedgerEntryType(this.safeString(item, 'type'));
2034
+ const status = this.parseLedgerEntryStatus(this.safeString(item, 'status'));
2035
+ const path = this.safeString(item, 'resource_path');
2036
+ let accountId = undefined;
2037
+ if (path !== undefined) {
2038
+ const parts = path.split('/');
2039
+ const numParts = parts.length;
2040
+ if (numParts > 3) {
2041
+ accountId = parts[3];
2042
+ }
2043
+ }
2044
+ return {
2045
+ 'info': item,
2046
+ 'id': id,
2047
+ 'timestamp': timestamp,
2048
+ 'datetime': this.iso8601(timestamp),
2049
+ 'direction': direction,
2050
+ 'account': accountId,
2051
+ 'referenceId': undefined,
2052
+ 'referenceAccount': undefined,
2053
+ 'type': type,
2054
+ 'currency': code,
2055
+ 'amount': this.parseNumber(amount),
2056
+ 'before': undefined,
2057
+ 'after': undefined,
2058
+ 'status': status,
2059
+ 'fee': fee,
2060
+ };
2061
+ }
2062
+ async findAccountId(code) {
2063
+ await this.loadMarkets();
2064
+ await this.loadAccounts();
2065
+ for (let i = 0; i < this.accounts.length; i++) {
2066
+ const account = this.accounts[i];
2067
+ if (account['code'] === code) {
2068
+ return account['id'];
2069
+ }
2070
+ }
2071
+ return undefined;
2072
+ }
2073
+ prepareAccountRequest(limit = undefined, params = {}) {
2074
+ const accountId = this.safeString2(params, 'account_id', 'accountId');
2075
+ if (accountId === undefined) {
2076
+ throw new errors.ArgumentsRequired(this.id + ' prepareAccountRequest() method requires an account_id (or accountId) parameter');
2077
+ }
2078
+ const request = {
2079
+ 'account_id': accountId,
2080
+ };
2081
+ if (limit !== undefined) {
2082
+ request['limit'] = limit;
2083
+ }
2084
+ return request;
2085
+ }
2086
+ async prepareAccountRequestWithCurrencyCode(code = undefined, limit = undefined, params = {}) {
2087
+ let accountId = this.safeString2(params, 'account_id', 'accountId');
2088
+ if (accountId === undefined) {
2089
+ if (code === undefined) {
2090
+ throw new errors.ArgumentsRequired(this.id + ' prepareAccountRequestWithCurrencyCode() method requires an account_id (or accountId) parameter OR a currency code argument');
2091
+ }
2092
+ accountId = await this.findAccountId(code);
2093
+ if (accountId === undefined) {
2094
+ throw new errors.ExchangeError(this.id + ' prepareAccountRequestWithCurrencyCode() could not find account id for ' + code);
2095
+ }
2096
+ }
2097
+ const request = {
2098
+ 'account_id': accountId,
2099
+ };
2100
+ if (limit !== undefined) {
2101
+ request['limit'] = limit;
2102
+ }
2103
+ return request;
2104
+ }
2105
+ async createMarketBuyOrderWithCost(symbol, cost, params = {}) {
2106
+ /**
2107
+ * @method
2108
+ * @name coinbase#createMarketBuyOrderWithCost
2109
+ * @description create a market buy order by providing the symbol and cost
2110
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_postorder
2111
+ * @param {string} symbol unified symbol of the market to create an order in
2112
+ * @param {float} cost how much you want to trade in units of the quote currency
2113
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2114
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2115
+ */
2116
+ await this.loadMarkets();
2117
+ const market = this.market(symbol);
2118
+ if (!market['spot']) {
2119
+ throw new errors.NotSupported(this.id + ' createMarketBuyOrderWithCost() supports spot orders only');
2120
+ }
2121
+ params['createMarketBuyOrderRequiresPrice'] = false;
2122
+ return await this.createOrder(symbol, 'market', 'buy', cost, undefined, params);
2123
+ }
2124
+ async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
2125
+ /**
2126
+ * @method
2127
+ * @name coinbase#createOrder
2128
+ * @description create a trade order
2129
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_postorder
2130
+ * @param {string} symbol unified symbol of the market to create an order in
2131
+ * @param {string} type 'market' or 'limit'
2132
+ * @param {string} side 'buy' or 'sell'
2133
+ * @param {float} amount how much you want to trade in units of the base currency, quote currency for 'market' 'buy' orders
2134
+ * @param {float} [price] the price to fulfill the order, in units of the quote currency, ignored in market orders
2135
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2136
+ * @param {float} [params.stopPrice] price to trigger stop orders
2137
+ * @param {float} [params.triggerPrice] price to trigger stop orders
2138
+ * @param {float} [params.stopLossPrice] price to trigger stop-loss orders
2139
+ * @param {float} [params.takeProfitPrice] price to trigger take-profit orders
2140
+ * @param {bool} [params.postOnly] true or false
2141
+ * @param {string} [params.timeInForce] 'GTC', 'IOC', 'GTD' or 'PO'
2142
+ * @param {string} [params.stop_direction] 'UNKNOWN_STOP_DIRECTION', 'STOP_DIRECTION_STOP_UP', 'STOP_DIRECTION_STOP_DOWN' the direction the stopPrice is triggered from
2143
+ * @param {string} [params.end_time] '2023-05-25T17:01:05.092Z' for 'GTD' orders
2144
+ * @param {float} [params.cost] *spot market buy only* the quote quantity that can be used as an alternative for the amount
2145
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2146
+ */
2147
+ await this.loadMarkets();
2148
+ const market = this.market(symbol);
2149
+ const request = {
2150
+ 'client_order_id': this.uuid(),
2151
+ 'product_id': market['id'],
2152
+ 'side': side.toUpperCase(),
2153
+ };
2154
+ const stopPrice = this.safeNumberN(params, ['stopPrice', 'stop_price', 'triggerPrice']);
2155
+ const stopLossPrice = this.safeNumber(params, 'stopLossPrice');
2156
+ const takeProfitPrice = this.safeNumber(params, 'takeProfitPrice');
2157
+ const isStop = stopPrice !== undefined;
2158
+ const isStopLoss = stopLossPrice !== undefined;
2159
+ const isTakeProfit = takeProfitPrice !== undefined;
2160
+ const timeInForce = this.safeString(params, 'timeInForce');
2161
+ const postOnly = (timeInForce === 'PO') ? true : this.safeValue2(params, 'postOnly', 'post_only', false);
2162
+ const endTime = this.safeString(params, 'end_time');
2163
+ let stopDirection = this.safeString(params, 'stop_direction');
2164
+ if (type === 'limit') {
2165
+ if (isStop) {
2166
+ if (stopDirection === undefined) {
2167
+ stopDirection = (side === 'buy') ? 'STOP_DIRECTION_STOP_DOWN' : 'STOP_DIRECTION_STOP_UP';
2168
+ }
2169
+ if ((timeInForce === 'GTD') || (endTime !== undefined)) {
2170
+ if (endTime === undefined) {
2171
+ throw new errors.ExchangeError(this.id + ' createOrder() requires an end_time parameter for a GTD order');
2172
+ }
2173
+ request['order_configuration'] = {
2174
+ 'stop_limit_stop_limit_gtd': {
2175
+ 'base_size': this.amountToPrecision(symbol, amount),
2176
+ 'limit_price': this.priceToPrecision(symbol, price),
2177
+ 'stop_price': this.priceToPrecision(symbol, stopPrice),
2178
+ 'stop_direction': stopDirection,
2179
+ 'end_time': endTime,
2180
+ },
2181
+ };
2182
+ }
2183
+ else {
2184
+ request['order_configuration'] = {
2185
+ 'stop_limit_stop_limit_gtc': {
2186
+ 'base_size': this.amountToPrecision(symbol, amount),
2187
+ 'limit_price': this.priceToPrecision(symbol, price),
2188
+ 'stop_price': this.priceToPrecision(symbol, stopPrice),
2189
+ 'stop_direction': stopDirection,
2190
+ },
2191
+ };
2192
+ }
2193
+ }
2194
+ else if (isStopLoss || isTakeProfit) {
2195
+ let triggerPrice = undefined;
2196
+ if (isStopLoss) {
2197
+ if (stopDirection === undefined) {
2198
+ stopDirection = (side === 'buy') ? 'STOP_DIRECTION_STOP_UP' : 'STOP_DIRECTION_STOP_DOWN';
2199
+ }
2200
+ triggerPrice = this.priceToPrecision(symbol, stopLossPrice);
2201
+ }
2202
+ else {
2203
+ if (stopDirection === undefined) {
2204
+ stopDirection = (side === 'buy') ? 'STOP_DIRECTION_STOP_DOWN' : 'STOP_DIRECTION_STOP_UP';
2205
+ }
2206
+ triggerPrice = this.priceToPrecision(symbol, takeProfitPrice);
2207
+ }
2208
+ request['order_configuration'] = {
2209
+ 'stop_limit_stop_limit_gtc': {
2210
+ 'base_size': this.amountToPrecision(symbol, amount),
2211
+ 'limit_price': this.priceToPrecision(symbol, price),
2212
+ 'stop_price': triggerPrice,
2213
+ 'stop_direction': stopDirection,
2214
+ },
2215
+ };
2216
+ }
2217
+ else {
2218
+ if ((timeInForce === 'GTD') || (endTime !== undefined)) {
2219
+ if (endTime === undefined) {
2220
+ throw new errors.ExchangeError(this.id + ' createOrder() requires an end_time parameter for a GTD order');
2221
+ }
2222
+ request['order_configuration'] = {
2223
+ 'limit_limit_gtd': {
2224
+ 'base_size': this.amountToPrecision(symbol, amount),
2225
+ 'limit_price': this.priceToPrecision(symbol, price),
2226
+ 'end_time': endTime,
2227
+ 'post_only': postOnly,
2228
+ },
2229
+ };
2230
+ }
2231
+ else {
2232
+ request['order_configuration'] = {
2233
+ 'limit_limit_gtc': {
2234
+ 'base_size': this.amountToPrecision(symbol, amount),
2235
+ 'limit_price': this.priceToPrecision(symbol, price),
2236
+ 'post_only': postOnly,
2237
+ },
2238
+ };
2239
+ }
2240
+ }
2241
+ }
2242
+ else {
2243
+ if (isStop || isStopLoss || isTakeProfit) {
2244
+ throw new errors.NotSupported(this.id + ' createOrder() only stop limit orders are supported');
2245
+ }
2246
+ if (side === 'buy') {
2247
+ let total = undefined;
2248
+ let createMarketBuyOrderRequiresPrice = true;
2249
+ [createMarketBuyOrderRequiresPrice, params] = this.handleOptionAndParams(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', true);
2250
+ const cost = this.safeNumber(params, 'cost');
2251
+ params = this.omit(params, 'cost');
2252
+ if (cost !== undefined) {
2253
+ total = this.costToPrecision(symbol, cost);
2254
+ }
2255
+ else if (createMarketBuyOrderRequiresPrice) {
2256
+ if (price === undefined) {
2257
+ throw new errors.InvalidOrder(this.id + ' createOrder() requires a price argument for market buy orders on spot markets to calculate the total amount to spend (amount * price), alternatively set the createMarketBuyOrderRequiresPrice option or param to false and pass the cost to spend in the amount argument');
2258
+ }
2259
+ else {
2260
+ const amountString = this.numberToString(amount);
2261
+ const priceString = this.numberToString(price);
2262
+ const costRequest = Precise["default"].stringMul(amountString, priceString);
2263
+ total = this.costToPrecision(symbol, costRequest);
2264
+ }
2265
+ }
2266
+ else {
2267
+ total = this.costToPrecision(symbol, amount);
2268
+ }
2269
+ request['order_configuration'] = {
2270
+ 'market_market_ioc': {
2271
+ 'quote_size': total,
2272
+ },
2273
+ };
2274
+ }
2275
+ else {
2276
+ request['order_configuration'] = {
2277
+ 'market_market_ioc': {
2278
+ 'base_size': this.amountToPrecision(symbol, amount),
2279
+ },
2280
+ };
2281
+ }
2282
+ }
2283
+ params = this.omit(params, ['timeInForce', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'stop_price', 'stopDirection', 'stop_direction', 'clientOrderId', 'postOnly', 'post_only', 'end_time']);
2284
+ const response = await this.v3PrivatePostBrokerageOrders(this.extend(request, params));
2285
+ //
2286
+ // successful order
2287
+ //
2288
+ // {
2289
+ // "success": true,
2290
+ // "failure_reason": "UNKNOWN_FAILURE_REASON",
2291
+ // "order_id": "52cfe5e2-0b29-4c19-a245-a6a773de5030",
2292
+ // "success_response": {
2293
+ // "order_id": "52cfe5e2-0b29-4c19-a245-a6a773de5030",
2294
+ // "product_id": "LTC-BTC",
2295
+ // "side": "SELL",
2296
+ // "client_order_id": "4d760580-6fca-4094-a70b-ebcca8626288"
2297
+ // },
2298
+ // "order_configuration": null
2299
+ // }
2300
+ //
2301
+ // failed order
2302
+ //
2303
+ // {
2304
+ // "success": false,
2305
+ // "failure_reason": "UNKNOWN_FAILURE_REASON",
2306
+ // "order_id": "",
2307
+ // "error_response": {
2308
+ // "error": "UNSUPPORTED_ORDER_CONFIGURATION",
2309
+ // "message": "source is not enabled for trading",
2310
+ // "error_details": "",
2311
+ // "new_order_failure_reason": "UNSUPPORTED_ORDER_CONFIGURATION"
2312
+ // },
2313
+ // "order_configuration": {
2314
+ // "limit_limit_gtc": {
2315
+ // "base_size": "100",
2316
+ // "limit_price": "40000",
2317
+ // "post_only": false
2318
+ // }
2319
+ // }
2320
+ // }
2321
+ //
2322
+ const success = this.safeValue(response, 'success');
2323
+ if (success !== true) {
2324
+ const errorResponse = this.safeValue(response, 'error_response');
2325
+ const errorTitle = this.safeString(errorResponse, 'error');
2326
+ const errorMessage = this.safeString(errorResponse, 'message');
2327
+ if (errorResponse !== undefined) {
2328
+ this.throwExactlyMatchedException(this.exceptions['exact'], errorTitle, errorMessage);
2329
+ this.throwBroadlyMatchedException(this.exceptions['broad'], errorTitle, errorMessage);
2330
+ throw new errors.ExchangeError(errorMessage);
2331
+ }
2332
+ }
2333
+ const data = this.safeValue(response, 'success_response', {});
2334
+ return this.parseOrder(data, market);
2335
+ }
2336
+ parseOrder(order, market = undefined) {
2337
+ //
2338
+ // createOrder
2339
+ //
2340
+ // {
2341
+ // "order_id": "52cfe5e2-0b29-4c19-a245-a6a773de5030",
2342
+ // "product_id": "LTC-BTC",
2343
+ // "side": "SELL",
2344
+ // "client_order_id": "4d760580-6fca-4094-a70b-ebcca8626288"
2345
+ // }
2346
+ //
2347
+ // cancelOrder, cancelOrders
2348
+ //
2349
+ // {
2350
+ // "success": true,
2351
+ // "failure_reason": "UNKNOWN_CANCEL_FAILURE_REASON",
2352
+ // "order_id": "bb8851a3-4fda-4a2c-aa06-9048db0e0f0d"
2353
+ // }
2354
+ //
2355
+ // fetchOrder, fetchOrders, fetchOpenOrders, fetchClosedOrders, fetchCanceledOrders
2356
+ //
2357
+ // {
2358
+ // "order_id": "9bc1eb3b-5b46-4b71-9628-ae2ed0cca75b",
2359
+ // "product_id": "LTC-BTC",
2360
+ // "user_id": "1111111-1111-1111-1111-111111111111",
2361
+ // "order_configuration": {
2362
+ // "limit_limit_gtc": {
2363
+ // "base_size": "0.2",
2364
+ // "limit_price": "0.006",
2365
+ // "post_only": false
2366
+ // },
2367
+ // "stop_limit_stop_limit_gtc": {
2368
+ // "base_size": "48.54",
2369
+ // "limit_price": "6.998",
2370
+ // "stop_price": "7.0687",
2371
+ // "stop_direction": "STOP_DIRECTION_STOP_DOWN"
2372
+ // }
2373
+ // },
2374
+ // "side": "SELL",
2375
+ // "client_order_id": "e5fe8482-05bb-428f-ad4d-dbc8ce39239c",
2376
+ // "status": "OPEN",
2377
+ // "time_in_force": "GOOD_UNTIL_CANCELLED",
2378
+ // "created_time": "2023-01-16T23:37:23.947030Z",
2379
+ // "completion_percentage": "0",
2380
+ // "filled_size": "0",
2381
+ // "average_filled_price": "0",
2382
+ // "fee": "",
2383
+ // "number_of_fills": "0",
2384
+ // "filled_value": "0",
2385
+ // "pending_cancel": false,
2386
+ // "size_in_quote": false,
2387
+ // "total_fees": "0",
2388
+ // "size_inclusive_of_fees": false,
2389
+ // "total_value_after_fees": "0",
2390
+ // "trigger_status": "INVALID_ORDER_TYPE",
2391
+ // "order_type": "LIMIT",
2392
+ // "reject_reason": "REJECT_REASON_UNSPECIFIED",
2393
+ // "settled": false,
2394
+ // "product_type": "SPOT",
2395
+ // "reject_message": "",
2396
+ // "cancel_message": ""
2397
+ // }
2398
+ //
2399
+ const marketId = this.safeString(order, 'product_id');
2400
+ const symbol = this.safeSymbol(marketId, market, '-');
2401
+ if (symbol !== undefined) {
2402
+ market = this.market(symbol);
2403
+ }
2404
+ const orderConfiguration = this.safeValue(order, 'order_configuration', {});
2405
+ const limitGTC = this.safeValue(orderConfiguration, 'limit_limit_gtc');
2406
+ const limitGTD = this.safeValue(orderConfiguration, 'limit_limit_gtd');
2407
+ const stopLimitGTC = this.safeValue(orderConfiguration, 'stop_limit_stop_limit_gtc');
2408
+ const stopLimitGTD = this.safeValue(orderConfiguration, 'stop_limit_stop_limit_gtd');
2409
+ const marketIOC = this.safeValue(orderConfiguration, 'market_market_ioc');
2410
+ const isLimit = ((limitGTC !== undefined) || (limitGTD !== undefined));
2411
+ const isStop = ((stopLimitGTC !== undefined) || (stopLimitGTD !== undefined));
2412
+ let price = undefined;
2413
+ let amount = undefined;
2414
+ let postOnly = undefined;
2415
+ let triggerPrice = undefined;
2416
+ if (isLimit) {
2417
+ const target = (limitGTC !== undefined) ? limitGTC : limitGTD;
2418
+ price = this.safeString(target, 'limit_price');
2419
+ amount = this.safeString(target, 'base_size');
2420
+ postOnly = this.safeValue(target, 'post_only');
2421
+ }
2422
+ else if (isStop) {
2423
+ const stopTarget = (stopLimitGTC !== undefined) ? stopLimitGTC : stopLimitGTD;
2424
+ price = this.safeString(stopTarget, 'limit_price');
2425
+ amount = this.safeString(stopTarget, 'base_size');
2426
+ postOnly = this.safeValue(stopTarget, 'post_only');
2427
+ triggerPrice = this.safeString(stopTarget, 'stop_price');
2428
+ }
2429
+ else {
2430
+ amount = this.safeString(marketIOC, 'base_size');
2431
+ }
2432
+ const datetime = this.safeString(order, 'created_time');
2433
+ const totalFees = this.safeString(order, 'total_fees');
2434
+ let currencyFee = undefined;
2435
+ if ((totalFees !== undefined) && (market !== undefined)) {
2436
+ currencyFee = market['quote'];
2437
+ }
2438
+ return this.safeOrder({
2439
+ 'info': order,
2440
+ 'id': this.safeString(order, 'order_id'),
2441
+ 'clientOrderId': this.safeString(order, 'client_order_id'),
2442
+ 'timestamp': this.parse8601(datetime),
2443
+ 'datetime': datetime,
2444
+ 'lastTradeTimestamp': undefined,
2445
+ 'symbol': symbol,
2446
+ 'type': this.parseOrderType(this.safeString(order, 'order_type')),
2447
+ 'timeInForce': this.parseTimeInForce(this.safeString(order, 'time_in_force')),
2448
+ 'postOnly': postOnly,
2449
+ 'side': this.safeStringLower(order, 'side'),
2450
+ 'price': price,
2451
+ 'stopPrice': triggerPrice,
2452
+ 'triggerPrice': triggerPrice,
2453
+ 'amount': amount,
2454
+ 'filled': this.safeString(order, 'filled_size'),
2455
+ 'remaining': undefined,
2456
+ 'cost': undefined,
2457
+ 'average': this.safeString(order, 'average_filled_price'),
2458
+ 'status': this.parseOrderStatus(this.safeString(order, 'status')),
2459
+ 'fee': {
2460
+ 'cost': this.safeString(order, 'total_fees'),
2461
+ 'currency': currencyFee,
2462
+ },
2463
+ 'trades': undefined,
2464
+ }, market);
2465
+ }
2466
+ parseOrderStatus(status) {
2467
+ const statuses = {
2468
+ 'OPEN': 'open',
2469
+ 'FILLED': 'closed',
2470
+ 'CANCELLED': 'canceled',
2471
+ 'EXPIRED': 'canceled',
2472
+ 'FAILED': 'canceled',
2473
+ 'UNKNOWN_ORDER_STATUS': undefined,
2474
+ };
2475
+ return this.safeString(statuses, status, status);
2476
+ }
2477
+ parseOrderType(type) {
2478
+ if (type === 'UNKNOWN_ORDER_TYPE') {
2479
+ return undefined;
2480
+ }
2481
+ const types = {
2482
+ 'MARKET': 'market',
2483
+ 'LIMIT': 'limit',
2484
+ 'STOP': 'limit',
2485
+ 'STOP_LIMIT': 'limit',
2486
+ };
2487
+ return this.safeString(types, type, type);
2488
+ }
2489
+ parseTimeInForce(timeInForce) {
2490
+ const timeInForces = {
2491
+ 'GOOD_UNTIL_CANCELLED': 'GTC',
2492
+ 'GOOD_UNTIL_DATE_TIME': 'GTD',
2493
+ 'IMMEDIATE_OR_CANCEL': 'IOC',
2494
+ 'FILL_OR_KILL': 'FOK',
2495
+ 'UNKNOWN_TIME_IN_FORCE': undefined,
2496
+ };
2497
+ return this.safeString(timeInForces, timeInForce, timeInForce);
2498
+ }
2499
+ async cancelOrder(id, symbol = undefined, params = {}) {
2500
+ /**
2501
+ * @method
2502
+ * @name coinbase#cancelOrder
2503
+ * @description cancels an open order
2504
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_cancelorders
2505
+ * @param {string} id order id
2506
+ * @param {string} symbol not used by coinbase cancelOrder()
2507
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2508
+ * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2509
+ */
2510
+ await this.loadMarkets();
2511
+ const orders = await this.cancelOrders([id], symbol, params);
2512
+ return this.safeValue(orders, 0, {});
2513
+ }
2514
+ async cancelOrders(ids, symbol = undefined, params = {}) {
2515
+ /**
2516
+ * @method
2517
+ * @name coinbase#cancelOrders
2518
+ * @description cancel multiple orders
2519
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_cancelorders
2520
+ * @param {string[]} ids order ids
2521
+ * @param {string} symbol not used by coinbase cancelOrders()
2522
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2523
+ * @returns {object} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2524
+ */
2525
+ await this.loadMarkets();
2526
+ let market = undefined;
2527
+ if (symbol !== undefined) {
2528
+ market = this.market(symbol);
2529
+ }
2530
+ const request = {
2531
+ 'order_ids': ids,
2532
+ };
2533
+ const response = await this.v3PrivatePostBrokerageOrdersBatchCancel(this.extend(request, params));
2534
+ //
2535
+ // {
2536
+ // "results": [
2537
+ // {
2538
+ // "success": true,
2539
+ // "failure_reason": "UNKNOWN_CANCEL_FAILURE_REASON",
2540
+ // "order_id": "bb8851a3-4fda-4a2c-aa06-9048db0e0f0d"
2541
+ // }
2542
+ // ]
2543
+ // }
2544
+ //
2545
+ const orders = this.safeValue(response, 'results', []);
2546
+ for (let i = 0; i < orders.length; i++) {
2547
+ const success = this.safeValue(orders[i], 'success');
2548
+ if (success !== true) {
2549
+ throw new errors.BadRequest(this.id + ' cancelOrders() has failed, check your arguments and parameters');
2550
+ }
2551
+ }
2552
+ return this.parseOrders(orders, market);
2553
+ }
2554
+ async editOrder(id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
2555
+ /**
2556
+ * @method
2557
+ * @name coinbase#editOrder
2558
+ * @description edit a trade order
2559
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_editorder
2560
+ * @param {string} id cancel order id
2561
+ * @param {string} symbol unified symbol of the market to create an order in
2562
+ * @param {string} type 'market' or 'limit'
2563
+ * @param {string} side 'buy' or 'sell'
2564
+ * @param {float} amount how much of currency you want to trade in units of base currency
2565
+ * @param {float} [price] the price at which the order is to be fullfilled, in units of the base currency, ignored in market orders
2566
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2567
+ * @param {boolean} [params.preview] default to false, wether to use the test/preview endpoint or not
2568
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2569
+ */
2570
+ await this.loadMarkets();
2571
+ const market = this.market(symbol);
2572
+ const request = {
2573
+ 'order_id': id,
2574
+ };
2575
+ if (amount !== undefined) {
2576
+ request['size'] = this.amountToPrecision(symbol, amount);
2577
+ }
2578
+ if (price !== undefined) {
2579
+ request['price'] = this.priceToPrecision(symbol, price);
2580
+ }
2581
+ const preview = this.safeValue2(params, 'preview', 'test', false);
2582
+ let response = undefined;
2583
+ if (preview) {
2584
+ params = this.omit(params, ['preview', 'test']);
2585
+ response = await this.v3PrivatePostBrokerageOrdersEditPreview(this.extend(request, params));
2586
+ }
2587
+ else {
2588
+ response = await this.v3PrivatePostBrokerageOrdersEdit(this.extend(request, params));
2589
+ }
2590
+ //
2591
+ // {
2592
+ // "success": true,
2593
+ // "errors": {
2594
+ // "edit_failure_reason": "UNKNOWN_EDIT_ORDER_FAILURE_REASON",
2595
+ // "preview_failure_reason": "UNKNOWN_PREVIEW_FAILURE_REASON"
2596
+ // }
2597
+ // }
2598
+ //
2599
+ return this.parseOrder(response, market);
2600
+ }
2601
+ async fetchOrder(id, symbol = undefined, params = {}) {
2602
+ /**
2603
+ * @method
2604
+ * @name coinbase#fetchOrder
2605
+ * @description fetches information on an order made by the user
2606
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_gethistoricalorder
2607
+ * @param {string} id the order id
2608
+ * @param {string} symbol unified market symbol that the order was made in
2609
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2610
+ * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2611
+ */
2612
+ await this.loadMarkets();
2613
+ let market = undefined;
2614
+ if (symbol !== undefined) {
2615
+ market = this.market(symbol);
2616
+ }
2617
+ const request = {
2618
+ 'order_id': id,
2619
+ };
2620
+ const response = await this.v3PrivateGetBrokerageOrdersHistoricalOrderId(this.extend(request, params));
2621
+ //
2622
+ // {
2623
+ // "order": {
2624
+ // "order_id": "9bc1eb3b-5b46-4b71-9628-ae2ed0cca75b",
2625
+ // "product_id": "LTC-BTC",
2626
+ // "user_id": "1111111-1111-1111-1111-111111111111",
2627
+ // "order_configuration": {
2628
+ // "limit_limit_gtc": {
2629
+ // "base_size": "0.2",
2630
+ // "limit_price": "0.006",
2631
+ // "post_only": false
2632
+ // }
2633
+ // },
2634
+ // "side": "SELL",
2635
+ // "client_order_id": "e5fe8482-05bb-428f-ad4d-dbc8ce39239c",
2636
+ // "status": "OPEN",
2637
+ // "time_in_force": "GOOD_UNTIL_CANCELLED",
2638
+ // "created_time": "2023-01-16T23:37:23.947030Z",
2639
+ // "completion_percentage": "0",
2640
+ // "filled_size": "0",
2641
+ // "average_filled_price": "0",
2642
+ // "fee": "",
2643
+ // "number_of_fills": "0",
2644
+ // "filled_value": "0",
2645
+ // "pending_cancel": false,
2646
+ // "size_in_quote": false,
2647
+ // "total_fees": "0",
2648
+ // "size_inclusive_of_fees": false,
2649
+ // "total_value_after_fees": "0",
2650
+ // "trigger_status": "INVALID_ORDER_TYPE",
2651
+ // "order_type": "LIMIT",
2652
+ // "reject_reason": "REJECT_REASON_UNSPECIFIED",
2653
+ // "settled": false,
2654
+ // "product_type": "SPOT",
2655
+ // "reject_message": "",
2656
+ // "cancel_message": ""
2657
+ // }
2658
+ // }
2659
+ //
2660
+ const order = this.safeValue(response, 'order', {});
2661
+ return this.parseOrder(order, market);
2662
+ }
2663
+ async fetchOrders(symbol = undefined, since = undefined, limit = 100, params = {}) {
2664
+ /**
2665
+ * @method
2666
+ * @name coinbase#fetchOrders
2667
+ * @description fetches information on multiple orders made by the user
2668
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_gethistoricalorders
2669
+ * @param {string} symbol unified market symbol that the orders were made in
2670
+ * @param {int} [since] the earliest time in ms to fetch orders
2671
+ * @param {int} [limit] the maximum number of order structures to retrieve
2672
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2673
+ * @param {int} [params.until] the latest time in ms to fetch trades for
2674
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
2675
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2676
+ */
2677
+ await this.loadMarkets();
2678
+ let paginate = false;
2679
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchOrders', 'paginate');
2680
+ if (paginate) {
2681
+ return await this.fetchPaginatedCallCursor('fetchOrders', symbol, since, limit, params, 'cursor', 'cursor', undefined, 100);
2682
+ }
2683
+ let market = undefined;
2684
+ if (symbol !== undefined) {
2685
+ market = this.market(symbol);
2686
+ }
2687
+ const request = {};
2688
+ if (market !== undefined) {
2689
+ request['product_id'] = market['id'];
2690
+ }
2691
+ if (limit !== undefined) {
2692
+ request['limit'] = limit;
2693
+ }
2694
+ if (since !== undefined) {
2695
+ request['start_date'] = this.iso8601(since);
2696
+ }
2697
+ const until = this.safeValueN(params, ['until', 'till']);
2698
+ if (until !== undefined) {
2699
+ params = this.omit(params, ['until', 'till']);
2700
+ request['end_date'] = this.iso8601(until);
2701
+ }
2702
+ const response = await this.v3PrivateGetBrokerageOrdersHistoricalBatch(this.extend(request, params));
2703
+ //
2704
+ // {
2705
+ // "orders": [
2706
+ // {
2707
+ // "order_id": "813a53c5-3e39-47bb-863d-2faf685d22d8",
2708
+ // "product_id": "BTC-USDT",
2709
+ // "user_id": "1111111-1111-1111-1111-111111111111",
2710
+ // "order_configuration": {
2711
+ // "market_market_ioc": {
2712
+ // "quote_size": "6.36"
2713
+ // }
2714
+ // },
2715
+ // "side": "BUY",
2716
+ // "client_order_id": "18eb9947-db49-4874-8e7b-39b8fe5f4317",
2717
+ // "status": "FILLED",
2718
+ // "time_in_force": "IMMEDIATE_OR_CANCEL",
2719
+ // "created_time": "2023-01-18T01:37:37.975552Z",
2720
+ // "completion_percentage": "100",
2721
+ // "filled_size": "0.000297920684505",
2722
+ // "average_filled_price": "21220.6399999973697697",
2723
+ // "fee": "",
2724
+ // "number_of_fills": "2",
2725
+ // "filled_value": "6.3220675944333996",
2726
+ // "pending_cancel": false,
2727
+ // "size_in_quote": true,
2728
+ // "total_fees": "0.0379324055666004",
2729
+ // "size_inclusive_of_fees": true,
2730
+ // "total_value_after_fees": "6.36",
2731
+ // "trigger_status": "INVALID_ORDER_TYPE",
2732
+ // "order_type": "MARKET",
2733
+ // "reject_reason": "REJECT_REASON_UNSPECIFIED",
2734
+ // "settled": true,
2735
+ // "product_type": "SPOT",
2736
+ // "reject_message": "",
2737
+ // "cancel_message": "Internal error"
2738
+ // },
2739
+ // ],
2740
+ // "sequence": "0",
2741
+ // "has_next": false,
2742
+ // "cursor": ""
2743
+ // }
2744
+ //
2745
+ const orders = this.safeValue(response, 'orders', []);
2746
+ const first = this.safeValue(orders, 0);
2747
+ const cursor = this.safeString(response, 'cursor');
2748
+ if ((cursor !== undefined) && (cursor !== '')) {
2749
+ first['cursor'] = cursor;
2750
+ orders[0] = first;
2751
+ }
2752
+ return this.parseOrders(orders, market, since, limit);
2753
+ }
2754
+ async fetchOrdersByStatus(status, symbol = undefined, since = undefined, limit = undefined, params = {}) {
2755
+ await this.loadMarkets();
2756
+ let market = undefined;
2757
+ if (symbol !== undefined) {
2758
+ market = this.market(symbol);
2759
+ }
2760
+ const request = {
2761
+ 'order_status': status,
2762
+ };
2763
+ if (market !== undefined) {
2764
+ request['product_id'] = market['id'];
2765
+ }
2766
+ if (limit === undefined) {
2767
+ limit = 100;
2768
+ }
2769
+ request['limit'] = limit;
2770
+ if (since !== undefined) {
2771
+ request['start_date'] = this.iso8601(since);
2772
+ }
2773
+ const until = this.safeValueN(params, ['until', 'till']);
2774
+ if (until !== undefined) {
2775
+ params = this.omit(params, ['until', 'till']);
2776
+ request['end_date'] = this.iso8601(until);
2777
+ }
2778
+ const response = await this.v3PrivateGetBrokerageOrdersHistoricalBatch(this.extend(request, params));
2779
+ //
2780
+ // {
2781
+ // "orders": [
2782
+ // {
2783
+ // "order_id": "813a53c5-3e39-47bb-863d-2faf685d22d8",
2784
+ // "product_id": "BTC-USDT",
2785
+ // "user_id": "1111111-1111-1111-1111-111111111111",
2786
+ // "order_configuration": {
2787
+ // "market_market_ioc": {
2788
+ // "quote_size": "6.36"
2789
+ // }
2790
+ // },
2791
+ // "side": "BUY",
2792
+ // "client_order_id": "18eb9947-db49-4874-8e7b-39b8fe5f4317",
2793
+ // "status": "FILLED",
2794
+ // "time_in_force": "IMMEDIATE_OR_CANCEL",
2795
+ // "created_time": "2023-01-18T01:37:37.975552Z",
2796
+ // "completion_percentage": "100",
2797
+ // "filled_size": "0.000297920684505",
2798
+ // "average_filled_price": "21220.6399999973697697",
2799
+ // "fee": "",
2800
+ // "number_of_fills": "2",
2801
+ // "filled_value": "6.3220675944333996",
2802
+ // "pending_cancel": false,
2803
+ // "size_in_quote": true,
2804
+ // "total_fees": "0.0379324055666004",
2805
+ // "size_inclusive_of_fees": true,
2806
+ // "total_value_after_fees": "6.36",
2807
+ // "trigger_status": "INVALID_ORDER_TYPE",
2808
+ // "order_type": "MARKET",
2809
+ // "reject_reason": "REJECT_REASON_UNSPECIFIED",
2810
+ // "settled": true,
2811
+ // "product_type": "SPOT",
2812
+ // "reject_message": "",
2813
+ // "cancel_message": "Internal error"
2814
+ // },
2815
+ // ],
2816
+ // "sequence": "0",
2817
+ // "has_next": false,
2818
+ // "cursor": ""
2819
+ // }
2820
+ //
2821
+ const orders = this.safeValue(response, 'orders', []);
2822
+ const first = this.safeValue(orders, 0);
2823
+ const cursor = this.safeString(response, 'cursor');
2824
+ if ((cursor !== undefined) && (cursor !== '')) {
2825
+ first['cursor'] = cursor;
2826
+ orders[0] = first;
2827
+ }
2828
+ return this.parseOrders(orders, market, since, limit);
2829
+ }
2830
+ async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
2831
+ /**
2832
+ * @method
2833
+ * @name coinbase#fetchOpenOrders
2834
+ * @description fetches information on all currently open orders
2835
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_gethistoricalorders
2836
+ * @param {string} symbol unified market symbol of the orders
2837
+ * @param {int} [since] timestamp in ms of the earliest order, default is undefined
2838
+ * @param {int} [limit] the maximum number of open order structures to retrieve
2839
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2840
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
2841
+ * @param {int} [params.until] the latest time in ms to fetch trades for
2842
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2843
+ */
2844
+ await this.loadMarkets();
2845
+ let paginate = false;
2846
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchOpenOrders', 'paginate');
2847
+ if (paginate) {
2848
+ return await this.fetchPaginatedCallCursor('fetchOpenOrders', symbol, since, limit, params, 'cursor', 'cursor', undefined, 100);
2849
+ }
2850
+ return await this.fetchOrdersByStatus('OPEN', symbol, since, limit, params);
2851
+ }
2852
+ async fetchClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
2853
+ /**
2854
+ * @method
2855
+ * @name coinbase#fetchClosedOrders
2856
+ * @description fetches information on multiple closed orders made by the user
2857
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_gethistoricalorders
2858
+ * @param {string} symbol unified market symbol of the orders
2859
+ * @param {int} [since] timestamp in ms of the earliest order, default is undefined
2860
+ * @param {int} [limit] the maximum number of closed order structures to retrieve
2861
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2862
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
2863
+ * @param {int} [params.until] the latest time in ms to fetch trades for
2864
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2865
+ */
2866
+ await this.loadMarkets();
2867
+ let paginate = false;
2868
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchClosedOrders', 'paginate');
2869
+ if (paginate) {
2870
+ return await this.fetchPaginatedCallCursor('fetchClosedOrders', symbol, since, limit, params, 'cursor', 'cursor', undefined, 100);
2871
+ }
2872
+ return await this.fetchOrdersByStatus('FILLED', symbol, since, limit, params);
2873
+ }
2874
+ async fetchCanceledOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
2875
+ /**
2876
+ * @method
2877
+ * @name coinbase#fetchCanceledOrders
2878
+ * @description fetches information on multiple canceled orders made by the user
2879
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_gethistoricalorders
2880
+ * @param {string} symbol unified market symbol of the orders
2881
+ * @param {int} [since] timestamp in ms of the earliest order, default is undefined
2882
+ * @param {int} [limit] the maximum number of canceled order structures to retrieve
2883
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2884
+ * @returns {object} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2885
+ */
2886
+ return await this.fetchOrdersByStatus('CANCELLED', symbol, since, limit, params);
2887
+ }
2888
+ async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
2889
+ /**
2890
+ * @method
2891
+ * @name coinbase#fetchOHLCV
2892
+ * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
2893
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getcandles
2894
+ * @param {string} symbol unified symbol of the market to fetch OHLCV data for
2895
+ * @param {string} timeframe the length of time each candle represents
2896
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
2897
+ * @param {int} [limit] the maximum amount of candles to fetch, not used by coinbase
2898
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2899
+ * @param {int} [params.until] the latest time in ms to fetch trades for
2900
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
2901
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
2902
+ */
2903
+ await this.loadMarkets();
2904
+ let paginate = false;
2905
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchOHLCV', 'paginate', false);
2906
+ if (paginate) {
2907
+ return await this.fetchPaginatedCallDeterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 299);
2908
+ }
2909
+ const market = this.market(symbol);
2910
+ const request = {
2911
+ 'product_id': market['id'],
2912
+ 'granularity': this.safeString(this.timeframes, timeframe, timeframe),
2913
+ };
2914
+ const until = this.safeValueN(params, ['until', 'till', 'end']);
2915
+ params = this.omit(params, ['until', 'till']);
2916
+ const duration = this.parseTimeframe(timeframe);
2917
+ const candles300 = 300 * duration;
2918
+ let sinceString = undefined;
2919
+ if (since !== undefined) {
2920
+ sinceString = this.numberToString(this.parseToInt(since / 1000));
2921
+ }
2922
+ else {
2923
+ const now = this.seconds().toString();
2924
+ sinceString = Precise["default"].stringSub(now, candles300.toString());
2925
+ }
2926
+ request['start'] = sinceString;
2927
+ let endString = this.numberToString(until);
2928
+ if (until === undefined) {
2929
+ // 300 candles max
2930
+ endString = Precise["default"].stringAdd(sinceString, candles300.toString());
2931
+ }
2932
+ request['end'] = endString;
2933
+ const response = await this.v3PrivateGetBrokerageProductsProductIdCandles(this.extend(request, params));
2934
+ //
2935
+ // {
2936
+ // "candles": [
2937
+ // {
2938
+ // "start": "1673391780",
2939
+ // "low": "17414.36",
2940
+ // "high": "17417.99",
2941
+ // "open": "17417.74",
2942
+ // "close": "17417.38",
2943
+ // "volume": "1.87780853"
2944
+ // },
2945
+ // ]
2946
+ // }
2947
+ //
2948
+ const candles = this.safeValue(response, 'candles', []);
2949
+ return this.parseOHLCVs(candles, market, timeframe, since, limit);
2950
+ }
2951
+ parseOHLCV(ohlcv, market = undefined) {
2952
+ //
2953
+ // [
2954
+ // {
2955
+ // "start": "1673391780",
2956
+ // "low": "17414.36",
2957
+ // "high": "17417.99",
2958
+ // "open": "17417.74",
2959
+ // "close": "17417.38",
2960
+ // "volume": "1.87780853"
2961
+ // },
2962
+ // ]
2963
+ //
2964
+ return [
2965
+ this.safeTimestamp(ohlcv, 'start'),
2966
+ this.safeNumber(ohlcv, 'open'),
2967
+ this.safeNumber(ohlcv, 'high'),
2968
+ this.safeNumber(ohlcv, 'low'),
2969
+ this.safeNumber(ohlcv, 'close'),
2970
+ this.safeNumber(ohlcv, 'volume'),
2971
+ ];
2972
+ }
2973
+ async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
2974
+ /**
2975
+ * @method
2976
+ * @name coinbase#fetchTrades
2977
+ * @description get the list of most recent trades for a particular symbol
2978
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getmarkettrades
2979
+ * @param {string} symbol unified market symbol of the trades
2980
+ * @param {int} [since] not used by coinbase fetchTrades
2981
+ * @param {int} [limit] the maximum number of trade structures to fetch
2982
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2983
+ * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
2984
+ */
2985
+ await this.loadMarkets();
2986
+ const market = this.market(symbol);
2987
+ const request = {
2988
+ 'product_id': market['id'],
2989
+ };
2990
+ if (limit !== undefined) {
2991
+ request['limit'] = limit;
2992
+ }
2993
+ const response = await this.v3PrivateGetBrokerageProductsProductIdTicker(this.extend(request, params));
2994
+ //
2995
+ // {
2996
+ // "trades": [
2997
+ // {
2998
+ // "trade_id": "10092327",
2999
+ // "product_id": "BTC-USDT",
3000
+ // "price": "17488.12",
3001
+ // "size": "0.0000623",
3002
+ // "time": "2023-01-11T00:52:37.557001Z",
3003
+ // "side": "BUY",
3004
+ // "bid": "",
3005
+ // "ask": ""
3006
+ // },
3007
+ // ]
3008
+ // }
3009
+ //
3010
+ const trades = this.safeValue(response, 'trades', []);
3011
+ return this.parseTrades(trades, market, since, limit);
3012
+ }
3013
+ async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
3014
+ /**
3015
+ * @method
3016
+ * @name coinbase#fetchMyTrades
3017
+ * @description fetch all trades made by the user
3018
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getfills
3019
+ * @param {string} symbol unified market symbol of the trades
3020
+ * @param {int} [since] timestamp in ms of the earliest order, default is undefined
3021
+ * @param {int} [limit] the maximum number of trade structures to fetch
3022
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3023
+ * @param {int} [params.until] the latest time in ms to fetch trades for
3024
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
3025
+ * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
3026
+ */
3027
+ await this.loadMarkets();
3028
+ let paginate = false;
3029
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchMyTrades', 'paginate');
3030
+ if (paginate) {
3031
+ return await this.fetchPaginatedCallCursor('fetchMyTrades', symbol, since, limit, params, 'cursor', 'cursor', undefined, 100);
3032
+ }
3033
+ let market = undefined;
3034
+ if (symbol !== undefined) {
3035
+ market = this.market(symbol);
3036
+ }
3037
+ const request = {};
3038
+ if (market !== undefined) {
3039
+ request['product_id'] = market['id'];
3040
+ }
3041
+ if (limit !== undefined) {
3042
+ request['limit'] = limit;
3043
+ }
3044
+ if (since !== undefined) {
3045
+ request['start_sequence_timestamp'] = this.iso8601(since);
3046
+ }
3047
+ const until = this.safeValueN(params, ['until', 'till']);
3048
+ if (until !== undefined) {
3049
+ params = this.omit(params, ['until', 'till']);
3050
+ request['end_sequence_timestamp'] = this.iso8601(until);
3051
+ }
3052
+ const response = await this.v3PrivateGetBrokerageOrdersHistoricalFills(this.extend(request, params));
3053
+ //
3054
+ // {
3055
+ // "fills": [
3056
+ // {
3057
+ // "entry_id": "b88b82cc89e326a2778874795102cbafd08dd979a2a7a3c69603fc4c23c2e010",
3058
+ // "trade_id": "cdc39e45-bbd3-44ec-bf02-61742dfb16a1",
3059
+ // "order_id": "813a53c5-3e39-47bb-863d-2faf685d22d8",
3060
+ // "trade_time": "2023-01-18T01:37:38.091377090Z",
3061
+ // "trade_type": "FILL",
3062
+ // "price": "21220.64",
3063
+ // "size": "0.0046830664333996",
3064
+ // "commission": "0.0000280983986004",
3065
+ // "product_id": "BTC-USDT",
3066
+ // "sequence_timestamp": "2023-01-18T01:37:38.092520Z",
3067
+ // "liquidity_indicator": "UNKNOWN_LIQUIDITY_INDICATOR",
3068
+ // "size_in_quote": true,
3069
+ // "user_id": "1111111-1111-1111-1111-111111111111",
3070
+ // "side": "BUY"
3071
+ // },
3072
+ // ],
3073
+ // "cursor": ""
3074
+ // }
3075
+ //
3076
+ const trades = this.safeValue(response, 'fills', []);
3077
+ const first = this.safeValue(trades, 0);
3078
+ const cursor = this.safeString(response, 'cursor');
3079
+ if ((cursor !== undefined) && (cursor !== '')) {
3080
+ first['cursor'] = cursor;
3081
+ trades[0] = first;
3082
+ }
3083
+ return this.parseTrades(trades, market, since, limit);
3084
+ }
3085
+ async fetchOrderBook(symbol, limit = undefined, params = {}) {
3086
+ /**
3087
+ * @method
3088
+ * @name coinbase#fetchOrderBook
3089
+ * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
3090
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getproductbook
3091
+ * @param {string} symbol unified symbol of the market to fetch the order book for
3092
+ * @param {int} [limit] the maximum amount of order book entries to return
3093
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3094
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
3095
+ */
3096
+ await this.loadMarkets();
3097
+ const market = this.market(symbol);
3098
+ const request = {
3099
+ 'product_id': market['id'],
3100
+ };
3101
+ if (limit !== undefined) {
3102
+ request['limit'] = limit;
3103
+ }
3104
+ const response = await this.v3PrivateGetBrokerageProductBook(this.extend(request, params));
3105
+ //
3106
+ // {
3107
+ // "pricebook": {
3108
+ // "product_id": "BTC-USDT",
3109
+ // "bids": [
3110
+ // {
3111
+ // "price": "30757.85",
3112
+ // "size": "0.115"
3113
+ // },
3114
+ // ],
3115
+ // "asks": [
3116
+ // {
3117
+ // "price": "30759.07",
3118
+ // "size": "0.04877659"
3119
+ // },
3120
+ // ],
3121
+ // "time": "2023-06-30T04:02:40.533606Z"
3122
+ // }
3123
+ // }
3124
+ //
3125
+ const data = this.safeValue(response, 'pricebook', {});
3126
+ const time = this.safeString(data, 'time');
3127
+ const timestamp = this.parse8601(time);
3128
+ return this.parseOrderBook(data, symbol, timestamp, 'bids', 'asks', 'price', 'size');
3129
+ }
3130
+ async fetchBidsAsks(symbols = undefined, params = {}) {
3131
+ /**
3132
+ * @method
3133
+ * @name coinbase#fetchBidsAsks
3134
+ * @description fetches the bid and ask price and volume for multiple markets
3135
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getbestbidask
3136
+ * @param {string[]} [symbols] unified symbols of the markets to fetch the bids and asks for, all markets are returned if not assigned
3137
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3138
+ * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
3139
+ */
3140
+ await this.loadMarkets();
3141
+ symbols = this.marketSymbols(symbols);
3142
+ // the 'product_ids' param isn't working properly and returns {"pricebooks":[]} when defined
3143
+ const response = await this.v3PrivateGetBrokerageBestBidAsk(params);
3144
+ //
3145
+ // {
3146
+ // "pricebooks": [
3147
+ // {
3148
+ // "product_id": "TRAC-EUR",
3149
+ // "bids": [
3150
+ // {
3151
+ // "price": "0.2384",
3152
+ // "size": "386.1"
3153
+ // }
3154
+ // ],
3155
+ // "asks": [
3156
+ // {
3157
+ // "price": "0.2406",
3158
+ // "size": "672"
3159
+ // }
3160
+ // ],
3161
+ // "time": "2023-06-30T07:15:24.656044Z"
3162
+ // },
3163
+ // ]
3164
+ // }
3165
+ //
3166
+ const tickers = this.safeValue(response, 'pricebooks', []);
3167
+ return this.parseTickers(tickers, symbols);
3168
+ }
3169
+ sign(path, api = [], method = 'GET', params = {}, headers = undefined, body = undefined) {
3170
+ const version = api[0];
3171
+ const signed = api[1] === 'private';
3172
+ const pathPart = (version === 'v3') ? 'api/v3' : 'v2';
3173
+ let fullPath = '/' + pathPart + '/' + this.implodeParams(path, params);
3174
+ const query = this.omit(params, this.extractParams(path));
3175
+ const savedPath = fullPath;
3176
+ if (method === 'GET') {
3177
+ if (Object.keys(query).length) {
3178
+ fullPath += '?' + this.urlencode(query);
3179
+ }
3180
+ }
3181
+ const url = this.urls['api']['rest'] + fullPath;
3182
+ if (signed) {
3183
+ const authorization = this.safeString(this.headers, 'Authorization');
3184
+ if (authorization !== undefined) {
3185
+ headers = {
3186
+ 'Authorization': authorization,
3187
+ 'Content-Type': 'application/json',
3188
+ };
3189
+ }
3190
+ else if (this.token) {
3191
+ headers = {
3192
+ 'Authorization': 'Bearer ' + this.token,
3193
+ 'Content-Type': 'application/json',
3194
+ };
3195
+ }
3196
+ else {
3197
+ this.checkRequiredCredentials();
3198
+ const nonce = this.nonce().toString();
3199
+ let payload = '';
3200
+ if (method !== 'GET') {
3201
+ if (Object.keys(query).length) {
3202
+ body = this.json(query);
3203
+ payload = body;
3204
+ }
3205
+ }
3206
+ let auth = undefined;
3207
+ if (version === 'v3') {
3208
+ auth = nonce + method + savedPath + payload;
3209
+ }
3210
+ else {
3211
+ auth = nonce + method + fullPath + payload;
3212
+ }
3213
+ const signature = this.hmac(this.encode(auth), this.encode(this.secret), sha256.sha256);
3214
+ headers = {
3215
+ 'CB-ACCESS-KEY': this.apiKey,
3216
+ 'CB-ACCESS-SIGN': signature,
3217
+ 'CB-ACCESS-TIMESTAMP': nonce,
3218
+ 'Content-Type': 'application/json',
3219
+ };
3220
+ }
3221
+ }
3222
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
3223
+ }
3224
+ handleErrors(code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
3225
+ if (response === undefined) {
3226
+ return undefined; // fallback to default error handler
3227
+ }
3228
+ const feedback = this.id + ' ' + body;
3229
+ //
3230
+ // {"error": "invalid_request", "error_description": "The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed."}
3231
+ //
3232
+ // or
3233
+ //
3234
+ // {
3235
+ // "errors": [
3236
+ // {
3237
+ // "id": "not_found",
3238
+ // "message": "Not found"
3239
+ // }
3240
+ // ]
3241
+ // }
3242
+ //
3243
+ let errorCode = this.safeString(response, 'error');
3244
+ if (errorCode !== undefined) {
3245
+ const errorMessage = this.safeString(response, 'error_description');
3246
+ this.throwExactlyMatchedException(this.exceptions['exact'], errorCode, feedback);
3247
+ this.throwBroadlyMatchedException(this.exceptions['broad'], errorMessage, feedback);
3248
+ throw new errors.ExchangeError(feedback);
3249
+ }
3250
+ const errors$1 = this.safeValue(response, 'errors');
3251
+ if (errors$1 !== undefined) {
3252
+ if (Array.isArray(errors$1)) {
3253
+ const numErrors = errors$1.length;
3254
+ if (numErrors > 0) {
3255
+ errorCode = this.safeString(errors$1[0], 'id');
3256
+ const errorMessage = this.safeString(errors$1[0], 'message');
3257
+ if (errorCode !== undefined) {
3258
+ this.throwExactlyMatchedException(this.exceptions['exact'], errorCode, feedback);
3259
+ this.throwBroadlyMatchedException(this.exceptions['broad'], errorMessage, feedback);
3260
+ throw new errors.ExchangeError(feedback);
3261
+ }
3262
+ }
3263
+ }
3264
+ }
3265
+ const advancedTrade = this.options['advanced'];
3266
+ const data = this.safeValue(response, 'data');
3267
+ if ((data === undefined) && (!advancedTrade)) {
3268
+ throw new errors.ExchangeError(this.id + ' failed due to a malformed response ' + this.json(response));
3269
+ }
3270
+ return undefined;
3271
+ }
3272
+ }
3273
+
3274
+ module.exports = coinbase;