ccxt 4.2.11 → 4.2.13

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 (392) hide show
  1. package/README.md +5 -5
  2. package/build.sh +2 -2
  3. package/dist/ccxt.browser.js +1347 -490
  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 +2209 -0
  125. package/dist/cjs/js/src/binance.js +9736 -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 +3807 -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 +8291 -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 +3424 -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 +7072 -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 +9049 -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 +761 -0
  185. package/dist/cjs/js/src/indodax.js +1069 -0
  186. package/dist/cjs/js/src/kraken.js +2857 -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 +2851 -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 +7330 -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 +4722 -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 +1608 -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 +1867 -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 +2765 -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/js/ccxt.d.ts +1 -1
  329. package/js/ccxt.js +1 -1
  330. package/js/src/abstract/bigone.d.ts +18 -0
  331. package/js/src/abstract/binance.d.ts +2 -0
  332. package/js/src/abstract/binancecoinm.d.ts +2 -0
  333. package/js/src/abstract/binanceus.d.ts +2 -0
  334. package/js/src/abstract/binanceusdm.d.ts +2 -0
  335. package/js/src/abstract/bingx.d.ts +2 -0
  336. package/js/src/abstract/bybit.d.ts +1 -0
  337. package/js/src/abstract/gate.d.ts +11 -0
  338. package/js/src/abstract/gateio.d.ts +11 -0
  339. package/js/src/abstract/okx.d.ts +1 -0
  340. package/js/src/alpaca.js +18 -18
  341. package/js/src/base/Exchange.d.ts +5 -1
  342. package/js/src/base/Exchange.js +101 -12
  343. package/js/src/bigone.d.ts +3 -2
  344. package/js/src/bigone.js +429 -167
  345. package/js/src/binance.js +48 -34
  346. package/js/src/bingx.js +115 -38
  347. package/js/src/bitfinex.d.ts +2 -2
  348. package/js/src/bitfinex.js +2 -3
  349. package/js/src/bitget.js +33 -13
  350. package/js/src/bitmart.d.ts +2 -2
  351. package/js/src/bitmart.js +5 -5
  352. package/js/src/bitmex.js +1 -0
  353. package/js/src/bybit.js +2 -0
  354. package/js/src/coinbase.d.ts +26 -3
  355. package/js/src/coinbase.js +176 -26
  356. package/js/src/coinlist.js +3 -4
  357. package/js/src/coinone.js +1 -1
  358. package/js/src/coinsph.js +2 -3
  359. package/js/src/deribit.js +1 -0
  360. package/js/src/gate.d.ts +4 -4
  361. package/js/src/gate.js +96 -59
  362. package/js/src/gemini.js +1 -1
  363. package/js/src/hitbtc.d.ts +4 -4
  364. package/js/src/hitbtc.js +2 -3
  365. package/js/src/htx.d.ts +1 -0
  366. package/js/src/htx.js +29 -7
  367. package/js/src/huobijp.js +2 -3
  368. package/js/src/independentreserve.js +7 -5
  369. package/js/src/kraken.js +3 -6
  370. package/js/src/lbank.js +59 -33
  371. package/js/src/mexc.js +2 -1
  372. package/js/src/oceanex.js +1 -1
  373. package/js/src/okx.js +14 -3
  374. package/js/src/phemex.js +9 -2
  375. package/js/src/pro/binance.d.ts +2 -23
  376. package/js/src/pro/binance.js +58 -22
  377. package/js/src/pro/coinbase.d.ts +2 -2
  378. package/js/src/pro/coinbase.js +4 -1
  379. package/js/src/pro/coinbasepro.d.ts +2 -2
  380. package/js/src/pro/hitbtc.d.ts +2 -2
  381. package/js/src/pro/kraken.js +1 -1
  382. package/js/src/pro/okx.d.ts +1 -0
  383. package/js/src/pro/okx.js +52 -2
  384. package/js/src/pro/poloniex.d.ts +2 -2
  385. package/js/src/probit.js +4 -2
  386. package/js/src/upbit.d.ts +3 -101
  387. package/js/src/upbit.js +12 -12
  388. package/js/src/wavesexchange.js +1 -1
  389. package/js/src/woo.d.ts +2 -0
  390. package/js/src/woo.js +52 -0
  391. package/package.json +1 -1
  392. package/skip-tests.json +5 -0
@@ -0,0 +1,3424 @@
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': true,
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
+ // withdraw
777
+ //
778
+ // {
779
+ // "id": "a1794ecf-5693-55fa-70cf-ef731748ed82",
780
+ // "type": "send",
781
+ // "status": "pending",
782
+ // "amount": {
783
+ // "amount": "-14.008308",
784
+ // "currency": "USDC"
785
+ // },
786
+ // "native_amount": {
787
+ // "amount": "-18.74",
788
+ // "currency": "CAD"
789
+ // },
790
+ // "description": null,
791
+ // "created_at": "2024-01-12T01:27:31Z",
792
+ // "updated_at": "2024-01-12T01:27:31Z",
793
+ // "resource": "transaction",
794
+ // "resource_path": "/v2/accounts/a34bgfad-ed67-538b-bffc-730c98c10da0/transactions/a1794ecf-5693-55fa-70cf-ef731748ed82",
795
+ // "instant_exchange": false,
796
+ // "network": {
797
+ // "status": "pending",
798
+ // "status_description": "Pending (est. less than 10 minutes)",
799
+ // "transaction_fee": {
800
+ // "amount": "4.008308",
801
+ // "currency": "USDC"
802
+ // },
803
+ // "transaction_amount": {
804
+ // "amount": "10.000000",
805
+ // "currency": "USDC"
806
+ // },
807
+ // "confirmations": 0
808
+ // },
809
+ // "to": {
810
+ // "resource": "ethereum_address",
811
+ // "address": "0x9...",
812
+ // "currency": "USDC",
813
+ // "address_info": {
814
+ // "address": "0x9..."
815
+ // }
816
+ // },
817
+ // "idem": "748d8591-dg9a-7831-a45b-crd61dg78762",
818
+ // "details": {
819
+ // "title": "Sent USDC",
820
+ // "subtitle": "To USDC address on Ethereum network",
821
+ // "header": "Sent 14.008308 USDC ($18.74)",
822
+ // "health": "warning"
823
+ // },
824
+ // "hide_native_amount": false
825
+ // }
826
+ //
827
+ const transactionType = this.safeString(transaction, 'type');
828
+ let amountAndCurrencyObject = undefined;
829
+ let feeObject = undefined;
830
+ if (transactionType === 'send') {
831
+ const network = this.safeValue(transaction, 'network', {});
832
+ amountAndCurrencyObject = this.safeValue(network, 'transaction_amount', {});
833
+ feeObject = this.safeValue(network, 'transaction_fee', {});
834
+ }
835
+ else {
836
+ amountAndCurrencyObject = this.safeValue(transaction, 'subtotal', {});
837
+ feeObject = this.safeValue(transaction, 'fee', {});
838
+ }
839
+ let status = this.parseTransactionStatus(this.safeString(transaction, 'status'));
840
+ if (status === undefined) {
841
+ const committed = this.safeValue(transaction, 'committed');
842
+ status = committed ? 'ok' : 'pending';
843
+ }
844
+ const id = this.safeString(transaction, 'id');
845
+ const currencyId = this.safeString(amountAndCurrencyObject, 'currency');
846
+ const feeCurrencyId = this.safeString(feeObject, 'currency');
847
+ const datetime = this.safeValue(transaction, 'created_at');
848
+ const toObject = this.safeValue(transaction, 'to', {});
849
+ const toAddress = this.safeString(toObject, 'address');
850
+ return {
851
+ 'info': transaction,
852
+ 'id': id,
853
+ 'txid': id,
854
+ 'timestamp': this.parse8601(datetime),
855
+ 'datetime': datetime,
856
+ 'network': undefined,
857
+ 'address': toAddress,
858
+ 'addressTo': toAddress,
859
+ 'addressFrom': undefined,
860
+ 'tag': undefined,
861
+ 'tagTo': undefined,
862
+ 'tagFrom': undefined,
863
+ 'type': this.safeString(transaction, 'resource'),
864
+ 'amount': this.safeNumber(amountAndCurrencyObject, 'amount'),
865
+ 'currency': this.safeCurrencyCode(currencyId, currency),
866
+ 'status': status,
867
+ 'updated': this.parse8601(this.safeValue(transaction, 'updated_at')),
868
+ 'fee': {
869
+ 'cost': this.safeNumber(feeObject, 'amount'),
870
+ 'currency': this.safeCurrencyCode(feeCurrencyId),
871
+ },
872
+ };
873
+ }
874
+ parseTrade(trade, market = undefined) {
875
+ //
876
+ // fetchMyBuys, fetchMySells
877
+ //
878
+ // {
879
+ // "id": "67e0eaec-07d7-54c4-a72c-2e92826897df",
880
+ // "status": "completed",
881
+ // "payment_method": {
882
+ // "id": "83562370-3e5c-51db-87da-752af5ab9559",
883
+ // "resource": "payment_method",
884
+ // "resource_path": "/v2/payment-methods/83562370-3e5c-51db-87da-752af5ab9559"
885
+ // },
886
+ // "transaction": {
887
+ // "id": "441b9494-b3f0-5b98-b9b0-4d82c21c252a",
888
+ // "resource": "transaction",
889
+ // "resource_path": "/v2/accounts/2bbf394c-193b-5b2a-9155-3b4732659ede/transactions/441b9494-b3f0-5b98-b9b0-4d82c21c252a"
890
+ // },
891
+ // "amount": { "amount": "1.00000000", "currency": "BTC" },
892
+ // "total": { "amount": "10.25", "currency": "USD" },
893
+ // "subtotal": { "amount": "10.10", "currency": "USD" },
894
+ // "created_at": "2015-01-31T20:49:02Z",
895
+ // "updated_at": "2015-02-11T16:54:02-08:00",
896
+ // "resource": "buy",
897
+ // "resource_path": "/v2/accounts/2bbf394c-193b-5b2a-9155-3b4732659ede/buys/67e0eaec-07d7-54c4-a72c-2e92826897df",
898
+ // "committed": true,
899
+ // "instant": false,
900
+ // "fee": { "amount": "0.15", "currency": "USD" },
901
+ // "payout_at": "2015-02-18T16:54:00-08:00"
902
+ // }
903
+ //
904
+ // fetchTrades
905
+ //
906
+ // {
907
+ // "trade_id": "10092327",
908
+ // "product_id": "BTC-USDT",
909
+ // "price": "17488.12",
910
+ // "size": "0.0000623",
911
+ // "time": "2023-01-11T00:52:37.557001Z",
912
+ // "side": "BUY",
913
+ // "bid": "",
914
+ // "ask": ""
915
+ // }
916
+ //
917
+ // fetchMyTrades
918
+ //
919
+ // {
920
+ // "entry_id": "b88b82cc89e326a2778874795102cbafd08dd979a2a7a3c69603fc4c23c2e010",
921
+ // "trade_id": "cdc39e45-bbd3-44ec-bf02-61742dfb16a1",
922
+ // "order_id": "813a53c5-3e39-47bb-863d-2faf685d22d8",
923
+ // "trade_time": "2023-01-18T01:37:38.091377090Z",
924
+ // "trade_type": "FILL",
925
+ // "price": "21220.64",
926
+ // "size": "0.0046830664333996",
927
+ // "commission": "0.0000280983986004",
928
+ // "product_id": "BTC-USDT",
929
+ // "sequence_timestamp": "2023-01-18T01:37:38.092520Z",
930
+ // "liquidity_indicator": "UNKNOWN_LIQUIDITY_INDICATOR",
931
+ // "size_in_quote": true,
932
+ // "user_id": "1111111-1111-1111-1111-111111111111",
933
+ // "side": "BUY"
934
+ // }
935
+ //
936
+ let symbol = undefined;
937
+ const totalObject = this.safeValue(trade, 'total', {});
938
+ const amountObject = this.safeValue(trade, 'amount', {});
939
+ const subtotalObject = this.safeValue(trade, 'subtotal', {});
940
+ const feeObject = this.safeValue(trade, 'fee', {});
941
+ const marketId = this.safeString(trade, 'product_id');
942
+ market = this.safeMarket(marketId, market, '-');
943
+ if (market !== undefined) {
944
+ symbol = market['symbol'];
945
+ }
946
+ else {
947
+ const baseId = this.safeString(amountObject, 'currency');
948
+ const quoteId = this.safeString(totalObject, 'currency');
949
+ if ((baseId !== undefined) && (quoteId !== undefined)) {
950
+ const base = this.safeCurrencyCode(baseId);
951
+ const quote = this.safeCurrencyCode(quoteId);
952
+ symbol = base + '/' + quote;
953
+ }
954
+ }
955
+ const sizeInQuote = this.safeValue(trade, 'size_in_quote');
956
+ const v3Price = this.safeString(trade, 'price');
957
+ let v3Cost = undefined;
958
+ let v3Amount = this.safeString(trade, 'size');
959
+ if (sizeInQuote) {
960
+ // calculate base size
961
+ v3Cost = v3Amount;
962
+ v3Amount = Precise["default"].stringDiv(v3Amount, v3Price);
963
+ }
964
+ const v3FeeCost = this.safeString(trade, 'commission');
965
+ const amountString = this.safeString(amountObject, 'amount', v3Amount);
966
+ const costString = this.safeString(subtotalObject, 'amount', v3Cost);
967
+ let priceString = undefined;
968
+ let cost = undefined;
969
+ if ((costString !== undefined) && (amountString !== undefined)) {
970
+ priceString = Precise["default"].stringDiv(costString, amountString);
971
+ }
972
+ else {
973
+ priceString = v3Price;
974
+ }
975
+ if ((priceString !== undefined) && (amountString !== undefined)) {
976
+ cost = Precise["default"].stringMul(priceString, amountString);
977
+ }
978
+ else {
979
+ cost = costString;
980
+ }
981
+ let feeCurrencyId = this.safeString(feeObject, 'currency');
982
+ const feeCost = this.safeNumber(feeObject, 'amount', this.parseNumber(v3FeeCost));
983
+ if ((feeCurrencyId === undefined) && (market !== undefined) && (feeCost !== undefined)) {
984
+ feeCurrencyId = market['quote'];
985
+ }
986
+ const datetime = this.safeStringN(trade, ['created_at', 'trade_time', 'time']);
987
+ const side = this.safeStringLower2(trade, 'resource', 'side');
988
+ const takerOrMaker = this.safeStringLower(trade, 'liquidity_indicator');
989
+ return this.safeTrade({
990
+ 'info': trade,
991
+ 'id': this.safeString2(trade, 'id', 'trade_id'),
992
+ 'order': this.safeString(trade, 'order_id'),
993
+ 'timestamp': this.parse8601(datetime),
994
+ 'datetime': datetime,
995
+ 'symbol': symbol,
996
+ 'type': undefined,
997
+ 'side': (side === 'unknown_order_side') ? undefined : side,
998
+ 'takerOrMaker': (takerOrMaker === 'unknown_liquidity_indicator') ? undefined : takerOrMaker,
999
+ 'price': priceString,
1000
+ 'amount': amountString,
1001
+ 'cost': cost,
1002
+ 'fee': {
1003
+ 'cost': feeCost,
1004
+ 'currency': this.safeCurrencyCode(feeCurrencyId),
1005
+ },
1006
+ });
1007
+ }
1008
+ async fetchMarkets(params = {}) {
1009
+ /**
1010
+ * @method
1011
+ * @name coinbase#fetchMarkets
1012
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getproducts
1013
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-currencies#get-fiat-currencies
1014
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-exchange-rates#get-exchange-rates
1015
+ * @description retrieves data on all markets for coinbase
1016
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1017
+ * @returns {object[]} an array of objects representing market data
1018
+ */
1019
+ const method = this.safeString(this.options, 'fetchMarkets', 'fetchMarketsV3');
1020
+ return await this[method](params);
1021
+ }
1022
+ async fetchMarketsV2(params = {}) {
1023
+ const response = await this.fetchCurrenciesFromCache(params);
1024
+ const currencies = this.safeValue(response, 'currencies', {});
1025
+ const exchangeRates = this.safeValue(response, 'exchangeRates', {});
1026
+ const data = this.safeValue(currencies, 'data', []);
1027
+ const dataById = this.indexBy(data, 'id');
1028
+ const rates = this.safeValue(this.safeValue(exchangeRates, 'data', {}), 'rates', {});
1029
+ const baseIds = Object.keys(rates);
1030
+ const result = [];
1031
+ for (let i = 0; i < baseIds.length; i++) {
1032
+ const baseId = baseIds[i];
1033
+ const base = this.safeCurrencyCode(baseId);
1034
+ const type = (baseId in dataById) ? 'fiat' : 'crypto';
1035
+ // https://github.com/ccxt/ccxt/issues/6066
1036
+ if (type === 'crypto') {
1037
+ for (let j = 0; j < data.length; j++) {
1038
+ const quoteCurrency = data[j];
1039
+ const quoteId = this.safeString(quoteCurrency, 'id');
1040
+ const quote = this.safeCurrencyCode(quoteId);
1041
+ result.push({
1042
+ 'id': baseId + '-' + quoteId,
1043
+ 'symbol': base + '/' + quote,
1044
+ 'base': base,
1045
+ 'quote': quote,
1046
+ 'settle': undefined,
1047
+ 'baseId': baseId,
1048
+ 'quoteId': quoteId,
1049
+ 'settleId': undefined,
1050
+ 'type': 'spot',
1051
+ 'spot': true,
1052
+ 'margin': false,
1053
+ 'swap': false,
1054
+ 'future': false,
1055
+ 'option': false,
1056
+ 'active': undefined,
1057
+ 'contract': false,
1058
+ 'linear': undefined,
1059
+ 'inverse': undefined,
1060
+ 'contractSize': undefined,
1061
+ 'expiry': undefined,
1062
+ 'expiryDatetime': undefined,
1063
+ 'strike': undefined,
1064
+ 'optionType': undefined,
1065
+ 'precision': {
1066
+ 'amount': undefined,
1067
+ 'price': undefined,
1068
+ },
1069
+ 'limits': {
1070
+ 'leverage': {
1071
+ 'min': undefined,
1072
+ 'max': undefined,
1073
+ },
1074
+ 'amount': {
1075
+ 'min': undefined,
1076
+ 'max': undefined,
1077
+ },
1078
+ 'price': {
1079
+ 'min': undefined,
1080
+ 'max': undefined,
1081
+ },
1082
+ 'cost': {
1083
+ 'min': this.safeNumber(quoteCurrency, 'min_size'),
1084
+ 'max': undefined,
1085
+ },
1086
+ },
1087
+ 'info': quoteCurrency,
1088
+ });
1089
+ }
1090
+ }
1091
+ }
1092
+ return result;
1093
+ }
1094
+ async fetchMarketsV3(params = {}) {
1095
+ const response = await this.v3PrivateGetBrokerageProducts(params);
1096
+ //
1097
+ // [
1098
+ // {
1099
+ // "product_id": "TONE-USD",
1100
+ // "price": "0.01523",
1101
+ // "price_percentage_change_24h": "1.94109772423025",
1102
+ // "volume_24h": "19773129",
1103
+ // "volume_percentage_change_24h": "437.0170530929949",
1104
+ // "base_increment": "1",
1105
+ // "quote_increment": "0.00001",
1106
+ // "quote_min_size": "1",
1107
+ // "quote_max_size": "10000000",
1108
+ // "base_min_size": "26.7187147229469674",
1109
+ // "base_max_size": "267187147.2294696735908216",
1110
+ // "base_name": "TE-FOOD",
1111
+ // "quote_name": "US Dollar",
1112
+ // "watched": false,
1113
+ // "is_disabled": false,
1114
+ // "new": false,
1115
+ // "status": "online",
1116
+ // "cancel_only": false,
1117
+ // "limit_only": false,
1118
+ // "post_only": false,
1119
+ // "trading_disabled": false,
1120
+ // "auction_mode": false,
1121
+ // "product_type": "SPOT",
1122
+ // "quote_currency_id": "USD",
1123
+ // "base_currency_id": "TONE",
1124
+ // "fcm_trading_session_details": null,
1125
+ // "mid_market_price": ""
1126
+ // },
1127
+ // ...
1128
+ // ]
1129
+ //
1130
+ const fees = await this.v3PrivateGetBrokerageTransactionSummary(params);
1131
+ //
1132
+ // {
1133
+ // "total_volume": 0,
1134
+ // "total_fees": 0,
1135
+ // "fee_tier": {
1136
+ // "pricing_tier": "",
1137
+ // "usd_from": "0",
1138
+ // "usd_to": "10000",
1139
+ // "taker_fee_rate": "0.006",
1140
+ // "maker_fee_rate": "0.004"
1141
+ // },
1142
+ // "margin_rate": null,
1143
+ // "goods_and_services_tax": null,
1144
+ // "advanced_trade_only_volume": 0,
1145
+ // "advanced_trade_only_fees": 0,
1146
+ // "coinbase_pro_volume": 0,
1147
+ // "coinbase_pro_fees": 0
1148
+ // }
1149
+ //
1150
+ const feeTier = this.safeValue(fees, 'fee_tier', {});
1151
+ const data = this.safeValue(response, 'products', []);
1152
+ const result = [];
1153
+ for (let i = 0; i < data.length; i++) {
1154
+ const market = data[i];
1155
+ const id = this.safeString(market, 'product_id');
1156
+ const baseId = this.safeString(market, 'base_currency_id');
1157
+ const quoteId = this.safeString(market, 'quote_currency_id');
1158
+ const base = this.safeCurrencyCode(baseId);
1159
+ const quote = this.safeCurrencyCode(quoteId);
1160
+ const marketType = this.safeStringLower(market, 'product_type');
1161
+ const tradingDisabled = this.safeValue(market, 'trading_disabled');
1162
+ const stablePairs = this.safeValue(this.options, 'stablePairs', []);
1163
+ result.push({
1164
+ 'id': id,
1165
+ 'symbol': base + '/' + quote,
1166
+ 'base': base,
1167
+ 'quote': quote,
1168
+ 'settle': undefined,
1169
+ 'baseId': baseId,
1170
+ 'quoteId': quoteId,
1171
+ 'settleId': undefined,
1172
+ 'type': marketType,
1173
+ 'spot': (marketType === 'spot'),
1174
+ 'margin': undefined,
1175
+ 'swap': false,
1176
+ 'future': false,
1177
+ 'option': false,
1178
+ 'active': !tradingDisabled,
1179
+ 'contract': false,
1180
+ 'linear': undefined,
1181
+ 'inverse': undefined,
1182
+ 'taker': this.inArray(id, stablePairs) ? 0.00001 : this.safeNumber(feeTier, 'taker_fee_rate'),
1183
+ 'maker': this.inArray(id, stablePairs) ? 0.0 : this.safeNumber(feeTier, 'maker_fee_rate'),
1184
+ 'contractSize': undefined,
1185
+ 'expiry': undefined,
1186
+ 'expiryDatetime': undefined,
1187
+ 'strike': undefined,
1188
+ 'optionType': undefined,
1189
+ 'precision': {
1190
+ 'amount': this.safeNumber(market, 'base_increment'),
1191
+ 'price': this.safeNumber2(market, 'price_increment', 'quote_increment'),
1192
+ },
1193
+ 'limits': {
1194
+ 'leverage': {
1195
+ 'min': undefined,
1196
+ 'max': undefined,
1197
+ },
1198
+ 'amount': {
1199
+ 'min': this.safeNumber(market, 'base_min_size'),
1200
+ 'max': this.safeNumber(market, 'base_max_size'),
1201
+ },
1202
+ 'price': {
1203
+ 'min': undefined,
1204
+ 'max': undefined,
1205
+ },
1206
+ 'cost': {
1207
+ 'min': this.safeNumber(market, 'quote_min_size'),
1208
+ 'max': this.safeNumber(market, 'quote_max_size'),
1209
+ },
1210
+ },
1211
+ 'created': undefined,
1212
+ 'info': market,
1213
+ });
1214
+ }
1215
+ return result;
1216
+ }
1217
+ async fetchCurrenciesFromCache(params = {}) {
1218
+ const options = this.safeValue(this.options, 'fetchCurrencies', {});
1219
+ const timestamp = this.safeInteger(options, 'timestamp');
1220
+ const expires = this.safeInteger(options, 'expires', 1000);
1221
+ const now = this.milliseconds();
1222
+ if ((timestamp === undefined) || ((now - timestamp) > expires)) {
1223
+ const currencies = await this.v2PublicGetCurrencies(params);
1224
+ const exchangeRates = await this.v2PublicGetExchangeRates(params);
1225
+ this.options['fetchCurrencies'] = this.extend(options, {
1226
+ 'currencies': currencies,
1227
+ 'exchangeRates': exchangeRates,
1228
+ 'timestamp': now,
1229
+ });
1230
+ }
1231
+ return this.safeValue(this.options, 'fetchCurrencies', {});
1232
+ }
1233
+ async fetchCurrencies(params = {}) {
1234
+ /**
1235
+ * @method
1236
+ * @name coinbase#fetchCurrencies
1237
+ * @description fetches all available currencies on an exchange
1238
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-currencies#get-fiat-currencies
1239
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-exchange-rates#get-exchange-rates
1240
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1241
+ * @returns {object} an associative dictionary of currencies
1242
+ */
1243
+ const response = await this.fetchCurrenciesFromCache(params);
1244
+ const currencies = this.safeValue(response, 'currencies', {});
1245
+ //
1246
+ // {
1247
+ // "data":[
1248
+ // {"id":"AED","name":"United Arab Emirates Dirham","min_size":"0.01000000"},
1249
+ // {"id":"AFN","name":"Afghan Afghani","min_size":"0.01000000"},
1250
+ // {"id":"ALL","name":"Albanian Lek","min_size":"0.01000000"},
1251
+ // {"id":"AMD","name":"Armenian Dram","min_size":"0.01000000"},
1252
+ // {"id":"ANG","name":"Netherlands Antillean Gulden","min_size":"0.01000000"},
1253
+ // ...
1254
+ // ],
1255
+ // }
1256
+ //
1257
+ const exchangeRates = this.safeValue(response, 'exchangeRates', {});
1258
+ //
1259
+ // {
1260
+ // "data":{
1261
+ // "currency":"USD",
1262
+ // "rates":{
1263
+ // "AED":"3.67",
1264
+ // "AFN":"78.21",
1265
+ // "ALL":"110.42",
1266
+ // "AMD":"474.18",
1267
+ // "ANG":"1.75",
1268
+ // ...
1269
+ // },
1270
+ // }
1271
+ // }
1272
+ //
1273
+ const data = this.safeValue(currencies, 'data', []);
1274
+ const dataById = this.indexBy(data, 'id');
1275
+ const rates = this.safeValue(this.safeValue(exchangeRates, 'data', {}), 'rates', {});
1276
+ const keys = Object.keys(rates);
1277
+ const result = {};
1278
+ for (let i = 0; i < keys.length; i++) {
1279
+ const key = keys[i];
1280
+ const type = (key in dataById) ? 'fiat' : 'crypto';
1281
+ const currency = this.safeValue(dataById, key, {});
1282
+ const id = this.safeString(currency, 'id', key);
1283
+ const name = this.safeString(currency, 'name');
1284
+ const code = this.safeCurrencyCode(id);
1285
+ result[code] = {
1286
+ 'id': id,
1287
+ 'code': code,
1288
+ 'info': currency,
1289
+ 'type': type,
1290
+ 'name': name,
1291
+ 'active': true,
1292
+ 'deposit': undefined,
1293
+ 'withdraw': undefined,
1294
+ 'fee': undefined,
1295
+ 'precision': undefined,
1296
+ 'limits': {
1297
+ 'amount': {
1298
+ 'min': this.safeNumber(currency, 'min_size'),
1299
+ 'max': undefined,
1300
+ },
1301
+ 'withdraw': {
1302
+ 'min': undefined,
1303
+ 'max': undefined,
1304
+ },
1305
+ },
1306
+ };
1307
+ }
1308
+ return result;
1309
+ }
1310
+ async fetchTickers(symbols = undefined, params = {}) {
1311
+ /**
1312
+ * @method
1313
+ * @name coinbase#fetchTickers
1314
+ * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
1315
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getproducts
1316
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-exchange-rates#get-exchange-rates
1317
+ * @param {string[]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1318
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1319
+ * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
1320
+ */
1321
+ const method = this.safeString(this.options, 'fetchTickers', 'fetchTickersV3');
1322
+ if (method === 'fetchTickersV3') {
1323
+ return await this.fetchTickersV3(symbols, params);
1324
+ }
1325
+ return await this.fetchTickersV2(symbols, params);
1326
+ }
1327
+ async fetchTickersV2(symbols = undefined, params = {}) {
1328
+ await this.loadMarkets();
1329
+ symbols = this.marketSymbols(symbols);
1330
+ const request = {
1331
+ // 'currency': 'USD',
1332
+ };
1333
+ const response = await this.v2PublicGetExchangeRates(this.extend(request, params));
1334
+ //
1335
+ // {
1336
+ // "data":{
1337
+ // "currency":"USD",
1338
+ // "rates":{
1339
+ // "AED":"3.6731",
1340
+ // "AFN":"103.163942",
1341
+ // "ALL":"106.973038",
1342
+ // }
1343
+ // }
1344
+ // }
1345
+ //
1346
+ const data = this.safeValue(response, 'data', {});
1347
+ const rates = this.safeValue(data, 'rates', {});
1348
+ const quoteId = this.safeString(data, 'currency');
1349
+ const result = {};
1350
+ const baseIds = Object.keys(rates);
1351
+ const delimiter = '-';
1352
+ for (let i = 0; i < baseIds.length; i++) {
1353
+ const baseId = baseIds[i];
1354
+ const marketId = baseId + delimiter + quoteId;
1355
+ const market = this.safeMarket(marketId, undefined, delimiter);
1356
+ const symbol = market['symbol'];
1357
+ result[symbol] = this.parseTicker(rates[baseId], market);
1358
+ }
1359
+ return this.filterByArrayTickers(result, 'symbol', symbols);
1360
+ }
1361
+ async fetchTickersV3(symbols = undefined, params = {}) {
1362
+ await this.loadMarkets();
1363
+ symbols = this.marketSymbols(symbols);
1364
+ const response = await this.v3PrivateGetBrokerageProducts(params);
1365
+ //
1366
+ // {
1367
+ // "products": [
1368
+ // {
1369
+ // "product_id": "TONE-USD",
1370
+ // "price": "0.01523",
1371
+ // "price_percentage_change_24h": "1.94109772423025",
1372
+ // "volume_24h": "19773129",
1373
+ // "volume_percentage_change_24h": "437.0170530929949",
1374
+ // "base_increment": "1",
1375
+ // "quote_increment": "0.00001",
1376
+ // "quote_min_size": "1",
1377
+ // "quote_max_size": "10000000",
1378
+ // "base_min_size": "26.7187147229469674",
1379
+ // "base_max_size": "267187147.2294696735908216",
1380
+ // "base_name": "TE-FOOD",
1381
+ // "quote_name": "US Dollar",
1382
+ // "watched": false,
1383
+ // "is_disabled": false,
1384
+ // "new": false,
1385
+ // "status": "online",
1386
+ // "cancel_only": false,
1387
+ // "limit_only": false,
1388
+ // "post_only": false,
1389
+ // "trading_disabled": false,
1390
+ // "auction_mode": false,
1391
+ // "product_type": "SPOT",
1392
+ // "quote_currency_id": "USD",
1393
+ // "base_currency_id": "TONE",
1394
+ // "fcm_trading_session_details": null,
1395
+ // "mid_market_price": ""
1396
+ // },
1397
+ // ...
1398
+ // ],
1399
+ // "num_products": 549
1400
+ // }
1401
+ //
1402
+ const data = this.safeValue(response, 'products', []);
1403
+ const result = {};
1404
+ for (let i = 0; i < data.length; i++) {
1405
+ const entry = data[i];
1406
+ const marketId = this.safeString(entry, 'product_id');
1407
+ const market = this.safeMarket(marketId, undefined, '-');
1408
+ const symbol = market['symbol'];
1409
+ result[symbol] = this.parseTicker(entry, market);
1410
+ }
1411
+ return this.filterByArrayTickers(result, 'symbol', symbols);
1412
+ }
1413
+ async fetchTicker(symbol, params = {}) {
1414
+ /**
1415
+ * @method
1416
+ * @name coinbase#fetchTicker
1417
+ * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
1418
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getmarkettrades
1419
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-prices#get-spot-price
1420
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-prices#get-buy-price
1421
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-prices#get-sell-price
1422
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
1423
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1424
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
1425
+ */
1426
+ const method = this.safeString(this.options, 'fetchTicker', 'fetchTickerV3');
1427
+ if (method === 'fetchTickerV3') {
1428
+ return await this.fetchTickerV3(symbol, params);
1429
+ }
1430
+ return await this.fetchTickerV2(symbol, params);
1431
+ }
1432
+ async fetchTickerV2(symbol, params = {}) {
1433
+ await this.loadMarkets();
1434
+ const market = this.market(symbol);
1435
+ const request = this.extend({
1436
+ 'symbol': market['id'],
1437
+ }, params);
1438
+ const spot = await this.v2PublicGetPricesSymbolSpot(request);
1439
+ //
1440
+ // {"data":{"base":"BTC","currency":"USD","amount":"48691.23"}}
1441
+ //
1442
+ const ask = await this.v2PublicGetPricesSymbolBuy(request);
1443
+ //
1444
+ // {"data":{"base":"BTC","currency":"USD","amount":"48691.23"}}
1445
+ //
1446
+ const bid = await this.v2PublicGetPricesSymbolSell(request);
1447
+ //
1448
+ // {"data":{"base":"BTC","currency":"USD","amount":"48691.23"}}
1449
+ //
1450
+ const spotData = this.safeValue(spot, 'data', {});
1451
+ const askData = this.safeValue(ask, 'data', {});
1452
+ const bidData = this.safeValue(bid, 'data', {});
1453
+ const bidAskLast = {
1454
+ 'bid': this.safeNumber(bidData, 'amount'),
1455
+ 'ask': this.safeNumber(askData, 'amount'),
1456
+ 'price': this.safeNumber(spotData, 'amount'),
1457
+ };
1458
+ return this.parseTicker(bidAskLast, market);
1459
+ }
1460
+ async fetchTickerV3(symbol, params = {}) {
1461
+ await this.loadMarkets();
1462
+ const market = this.market(symbol);
1463
+ const request = {
1464
+ 'product_id': market['id'],
1465
+ 'limit': 1,
1466
+ };
1467
+ const response = await this.v3PrivateGetBrokerageProductsProductIdTicker(this.extend(request, params));
1468
+ //
1469
+ // {
1470
+ // "trades": [
1471
+ // {
1472
+ // "trade_id": "518078013",
1473
+ // "product_id": "BTC-USD",
1474
+ // "price": "28208.1",
1475
+ // "size": "0.00659179",
1476
+ // "time": "2023-04-04T23:05:34.492746Z",
1477
+ // "side": "BUY",
1478
+ // "bid": "",
1479
+ // "ask": ""
1480
+ // }
1481
+ // ],
1482
+ // "best_bid": "28208.61",
1483
+ // "best_ask": "28208.62"
1484
+ // }
1485
+ //
1486
+ const data = this.safeValue(response, 'trades', []);
1487
+ const ticker = this.parseTicker(data[0], market);
1488
+ ticker['bid'] = this.safeNumber(response, 'best_bid');
1489
+ ticker['ask'] = this.safeNumber(response, 'best_ask');
1490
+ return ticker;
1491
+ }
1492
+ parseTicker(ticker, market = undefined) {
1493
+ //
1494
+ // fetchTickerV2
1495
+ //
1496
+ // {
1497
+ // "bid": 20713.37,
1498
+ // "ask": 20924.65,
1499
+ // "price": 20809.83
1500
+ // }
1501
+ //
1502
+ // fetchTickerV3
1503
+ //
1504
+ // {
1505
+ // "trade_id": "10209805",
1506
+ // "product_id": "BTC-USDT",
1507
+ // "price": "19381.27",
1508
+ // "size": "0.1",
1509
+ // "time": "2023-01-13T20:35:41.865970Z",
1510
+ // "side": "BUY",
1511
+ // "bid": "",
1512
+ // "ask": ""
1513
+ // }
1514
+ //
1515
+ // fetchTickersV2
1516
+ //
1517
+ // "48691.23"
1518
+ //
1519
+ // fetchTickersV3
1520
+ //
1521
+ // [
1522
+ // {
1523
+ // "product_id": "TONE-USD",
1524
+ // "price": "0.01523",
1525
+ // "price_percentage_change_24h": "1.94109772423025",
1526
+ // "volume_24h": "19773129",
1527
+ // "volume_percentage_change_24h": "437.0170530929949",
1528
+ // "base_increment": "1",
1529
+ // "quote_increment": "0.00001",
1530
+ // "quote_min_size": "1",
1531
+ // "quote_max_size": "10000000",
1532
+ // "base_min_size": "26.7187147229469674",
1533
+ // "base_max_size": "267187147.2294696735908216",
1534
+ // "base_name": "TE-FOOD",
1535
+ // "quote_name": "US Dollar",
1536
+ // "watched": false,
1537
+ // "is_disabled": false,
1538
+ // "new": false,
1539
+ // "status": "online",
1540
+ // "cancel_only": false,
1541
+ // "limit_only": false,
1542
+ // "post_only": false,
1543
+ // "trading_disabled": false,
1544
+ // "auction_mode": false,
1545
+ // "product_type": "SPOT",
1546
+ // "quote_currency_id": "USD",
1547
+ // "base_currency_id": "TONE",
1548
+ // "fcm_trading_session_details": null,
1549
+ // "mid_market_price": ""
1550
+ // },
1551
+ // ...
1552
+ // ]
1553
+ //
1554
+ // fetchBidsAsks
1555
+ //
1556
+ // {
1557
+ // "product_id": "TRAC-EUR",
1558
+ // "bids": [
1559
+ // {
1560
+ // "price": "0.2384",
1561
+ // "size": "386.1"
1562
+ // }
1563
+ // ],
1564
+ // "asks": [
1565
+ // {
1566
+ // "price": "0.2406",
1567
+ // "size": "672"
1568
+ // }
1569
+ // ],
1570
+ // "time": "2023-06-30T07:15:24.656044Z"
1571
+ // }
1572
+ //
1573
+ let bid = this.safeNumber(ticker, 'bid');
1574
+ let ask = this.safeNumber(ticker, 'ask');
1575
+ let bidVolume = undefined;
1576
+ let askVolume = undefined;
1577
+ if (('bids' in ticker)) {
1578
+ const bids = this.safeValue(ticker, 'bids', []);
1579
+ const asks = this.safeValue(ticker, 'asks', []);
1580
+ bid = this.safeNumber(bids[0], 'price');
1581
+ bidVolume = this.safeNumber(bids[0], 'size');
1582
+ ask = this.safeNumber(asks[0], 'price');
1583
+ askVolume = this.safeNumber(asks[0], 'size');
1584
+ }
1585
+ const marketId = this.safeString(ticker, 'product_id');
1586
+ const last = this.safeNumber(ticker, 'price');
1587
+ const datetime = this.safeString(ticker, 'time');
1588
+ return this.safeTicker({
1589
+ 'symbol': this.safeSymbol(marketId, market),
1590
+ 'timestamp': this.parse8601(datetime),
1591
+ 'datetime': datetime,
1592
+ 'bid': bid,
1593
+ 'ask': ask,
1594
+ 'last': last,
1595
+ 'high': undefined,
1596
+ 'low': undefined,
1597
+ 'bidVolume': bidVolume,
1598
+ 'askVolume': askVolume,
1599
+ 'vwap': undefined,
1600
+ 'open': undefined,
1601
+ 'close': last,
1602
+ 'previousClose': undefined,
1603
+ 'change': undefined,
1604
+ 'percentage': this.safeNumber(ticker, 'price_percentage_change_24h'),
1605
+ 'average': undefined,
1606
+ 'baseVolume': undefined,
1607
+ 'quoteVolume': undefined,
1608
+ 'info': ticker,
1609
+ }, market);
1610
+ }
1611
+ parseBalance(response, params = {}) {
1612
+ const balances = this.safeValue2(response, 'data', 'accounts', []);
1613
+ const accounts = this.safeValue(params, 'type', this.options['accounts']);
1614
+ const v3Accounts = this.safeValue(params, 'type', this.options['v3Accounts']);
1615
+ const result = { 'info': response };
1616
+ for (let b = 0; b < balances.length; b++) {
1617
+ const balance = balances[b];
1618
+ const type = this.safeString(balance, 'type');
1619
+ if (this.inArray(type, accounts)) {
1620
+ const value = this.safeValue(balance, 'balance');
1621
+ if (value !== undefined) {
1622
+ const currencyId = this.safeString(value, 'currency');
1623
+ const code = this.safeCurrencyCode(currencyId);
1624
+ const total = this.safeString(value, 'amount');
1625
+ const free = total;
1626
+ let account = this.safeValue(result, code);
1627
+ if (account === undefined) {
1628
+ account = this.account();
1629
+ account['free'] = free;
1630
+ account['total'] = total;
1631
+ }
1632
+ else {
1633
+ account['free'] = Precise["default"].stringAdd(account['free'], total);
1634
+ account['total'] = Precise["default"].stringAdd(account['total'], total);
1635
+ }
1636
+ result[code] = account;
1637
+ }
1638
+ }
1639
+ else if (this.inArray(type, v3Accounts)) {
1640
+ const available = this.safeValue(balance, 'available_balance');
1641
+ const hold = this.safeValue(balance, 'hold');
1642
+ if (available !== undefined && hold !== undefined) {
1643
+ const currencyId = this.safeString(available, 'currency');
1644
+ const code = this.safeCurrencyCode(currencyId);
1645
+ const used = this.safeString(hold, 'value');
1646
+ const free = this.safeString(available, 'value');
1647
+ const total = Precise["default"].stringAdd(used, free);
1648
+ let account = this.safeValue(result, code);
1649
+ if (account === undefined) {
1650
+ account = this.account();
1651
+ account['free'] = free;
1652
+ account['used'] = used;
1653
+ account['total'] = total;
1654
+ }
1655
+ else {
1656
+ account['free'] = Precise["default"].stringAdd(account['free'], free);
1657
+ account['used'] = Precise["default"].stringAdd(account['used'], used);
1658
+ account['total'] = Precise["default"].stringAdd(account['total'], total);
1659
+ }
1660
+ result[code] = account;
1661
+ }
1662
+ }
1663
+ }
1664
+ return this.safeBalance(result);
1665
+ }
1666
+ async fetchBalance(params = {}) {
1667
+ /**
1668
+ * @method
1669
+ * @name coinbase#fetchBalance
1670
+ * @description query for balance and get the amount of funds available for trading or funds locked in orders
1671
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getaccounts
1672
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-accounts#list-accounts
1673
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1674
+ * @param {boolean} [params.v3] default false, set true to use v3 api endpoint
1675
+ * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
1676
+ */
1677
+ await this.loadMarkets();
1678
+ const request = {
1679
+ 'limit': 250,
1680
+ };
1681
+ let response = undefined;
1682
+ const isV3 = this.safeValue(params, 'v3', false);
1683
+ params = this.omit(params, 'v3');
1684
+ const method = this.safeString(this.options, 'fetchBalance', 'v3PrivateGetBrokerageAccounts');
1685
+ if ((isV3) || (method === 'v3PrivateGetBrokerageAccounts')) {
1686
+ response = await this.v3PrivateGetBrokerageAccounts(this.extend(request, params));
1687
+ }
1688
+ else {
1689
+ response = await this.v2PrivateGetAccounts(this.extend(request, params));
1690
+ }
1691
+ //
1692
+ // v2PrivateGetAccounts
1693
+ // {
1694
+ // "pagination":{
1695
+ // "ending_before":null,
1696
+ // "starting_after":null,
1697
+ // "previous_ending_before":null,
1698
+ // "next_starting_after":"6b17acd6-2e68-5eb0-9f45-72d67cef578b",
1699
+ // "limit":100,
1700
+ // "order":"desc",
1701
+ // "previous_uri":null,
1702
+ // "next_uri":"/v2/accounts?limit=100\u0026starting_after=6b17acd6-2e68-5eb0-9f45-72d67cef578b"
1703
+ // },
1704
+ // "data":[
1705
+ // {
1706
+ // "id":"94ad58bc-0f15-5309-b35a-a4c86d7bad60",
1707
+ // "name":"MINA Wallet",
1708
+ // "primary":false,
1709
+ // "type":"wallet",
1710
+ // "currency":{
1711
+ // "code":"MINA",
1712
+ // "name":"Mina",
1713
+ // "color":"#EA6B48",
1714
+ // "sort_index":397,
1715
+ // "exponent":9,
1716
+ // "type":"crypto",
1717
+ // "address_regex":"^(B62)[A-Za-z0-9]{52}$",
1718
+ // "asset_id":"a4ffc575-942c-5e26-b70c-cb3befdd4229",
1719
+ // "slug":"mina"
1720
+ // },
1721
+ // "balance":{"amount":"0.000000000","currency":"MINA"},
1722
+ // "created_at":"2022-03-25T00:36:16Z",
1723
+ // "updated_at":"2022-03-25T00:36:16Z",
1724
+ // "resource":"account",
1725
+ // "resource_path":"/v2/accounts/94ad58bc-0f15-5309-b35a-a4c86d7bad60",
1726
+ // "allow_deposits":true,
1727
+ // "allow_withdrawals":true
1728
+ // },
1729
+ // ]
1730
+ // }
1731
+ //
1732
+ // v3PrivateGetBrokerageAccounts
1733
+ // {
1734
+ // "accounts": [
1735
+ // {
1736
+ // "uuid": "11111111-1111-1111-1111-111111111111",
1737
+ // "name": "USDC Wallet",
1738
+ // "currency": "USDC",
1739
+ // "available_balance": {
1740
+ // "value": "0.0000000000000000",
1741
+ // "currency": "USDC"
1742
+ // },
1743
+ // "default": true,
1744
+ // "active": true,
1745
+ // "created_at": "2023-01-04T06:20:06.456Z",
1746
+ // "updated_at": "2023-01-04T06:20:07.181Z",
1747
+ // "deleted_at": null,
1748
+ // "type": "ACCOUNT_TYPE_CRYPTO",
1749
+ // "ready": false,
1750
+ // "hold": {
1751
+ // "value": "0.0000000000000000",
1752
+ // "currency": "USDC"
1753
+ // }
1754
+ // },
1755
+ // ...
1756
+ // ],
1757
+ // "has_next": false,
1758
+ // "cursor": "",
1759
+ // "size": 9
1760
+ // }
1761
+ //
1762
+ return this.parseBalance(response, params);
1763
+ }
1764
+ async fetchLedger(code = undefined, since = undefined, limit = undefined, params = {}) {
1765
+ /**
1766
+ * @method
1767
+ * @name coinbase#fetchLedger
1768
+ * @description fetch the history of changes, actions done by the user or operations that altered balance of the user
1769
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-transactions#list-transactions
1770
+ * @param {string} code unified currency code, default is undefined
1771
+ * @param {int} [since] timestamp in ms of the earliest ledger entry, default is undefined
1772
+ * @param {int} [limit] max number of ledger entrys to return, default is undefined
1773
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1774
+ * @returns {object} a [ledger structure]{@link https://docs.ccxt.com/#/?id=ledger-structure}
1775
+ */
1776
+ await this.loadMarkets();
1777
+ let currency = undefined;
1778
+ if (code !== undefined) {
1779
+ currency = this.currency(code);
1780
+ }
1781
+ const request = await this.prepareAccountRequestWithCurrencyCode(code, limit, params);
1782
+ const query = this.omit(params, ['account_id', 'accountId']);
1783
+ // for pagination use parameter 'starting_after'
1784
+ // the value for the next page can be obtained from the result of the previous call in the 'pagination' field
1785
+ // eg: instance.last_json_response.pagination.next_starting_after
1786
+ const response = await this.v2PrivateGetAccountsAccountIdTransactions(this.extend(request, query));
1787
+ return this.parseLedger(response['data'], currency, since, limit);
1788
+ }
1789
+ parseLedgerEntryStatus(status) {
1790
+ const types = {
1791
+ 'completed': 'ok',
1792
+ };
1793
+ return this.safeString(types, status, status);
1794
+ }
1795
+ parseLedgerEntryType(type) {
1796
+ const types = {
1797
+ 'buy': 'trade',
1798
+ 'sell': 'trade',
1799
+ 'fiat_deposit': 'transaction',
1800
+ 'fiat_withdrawal': 'transaction',
1801
+ 'exchange_deposit': 'transaction',
1802
+ 'exchange_withdrawal': 'transaction',
1803
+ 'send': 'transaction',
1804
+ 'pro_deposit': 'transaction',
1805
+ 'pro_withdrawal': 'transaction', // crypto deposit (to coinbase from coinbasepro)
1806
+ };
1807
+ return this.safeString(types, type, type);
1808
+ }
1809
+ parseLedgerEntry(item, currency = undefined) {
1810
+ //
1811
+ // crypto deposit transaction
1812
+ //
1813
+ // {
1814
+ // "id": "34e4816b-4c8c-5323-a01c-35a9fa26e490",
1815
+ // "type": "send",
1816
+ // "status": "completed",
1817
+ // "amount": { amount: "28.31976528", currency: "BCH" },
1818
+ // "native_amount": { amount: "2799.65", currency: "GBP" },
1819
+ // "description": null,
1820
+ // "created_at": "2019-02-28T12:35:20Z",
1821
+ // "updated_at": "2019-02-28T12:43:24Z",
1822
+ // "resource": "transaction",
1823
+ // "resource_path": "/v2/accounts/c01d7364-edd7-5f3a-bd1d-de53d4cbb25e/transactions/34e4816b-4c8c-5323-a01c-35a9fa26e490",
1824
+ // "instant_exchange": false,
1825
+ // "network": {
1826
+ // "status": "confirmed",
1827
+ // "hash": "56222d865dae83774fccb2efbd9829cf08c75c94ce135bfe4276f3fb46d49701",
1828
+ // "transaction_url": "https://bch.btc.com/56222d865dae83774fccb2efbd9829cf08c75c94ce135bfe4276f3fb46d49701"
1829
+ // },
1830
+ // "from": { resource: "bitcoin_cash_network", currency: "BCH" },
1831
+ // "details": { title: 'Received Bitcoin Cash', subtitle: "From Bitcoin Cash address" }
1832
+ // }
1833
+ //
1834
+ // crypto withdrawal transaction
1835
+ //
1836
+ // {
1837
+ // "id": "459aad99-2c41-5698-ac71-b6b81a05196c",
1838
+ // "type": "send",
1839
+ // "status": "completed",
1840
+ // "amount": { amount: "-0.36775642", currency: "BTC" },
1841
+ // "native_amount": { amount: "-1111.65", currency: "GBP" },
1842
+ // "description": null,
1843
+ // "created_at": "2019-03-20T08:37:07Z",
1844
+ // "updated_at": "2019-03-20T08:49:33Z",
1845
+ // "resource": "transaction",
1846
+ // "resource_path": "/v2/accounts/c6afbd34-4bd0-501e-8616-4862c193cd84/transactions/459aad99-2c41-5698-ac71-b6b81a05196c",
1847
+ // "instant_exchange": false,
1848
+ // "network": {
1849
+ // "status": "confirmed",
1850
+ // "hash": "2732bbcf35c69217c47b36dce64933d103895277fe25738ffb9284092701e05b",
1851
+ // "transaction_url": "https://blockchain.info/tx/2732bbcf35c69217c47b36dce64933d103895277fe25738ffb9284092701e05b",
1852
+ // "transaction_fee": { amount: "0.00000000", currency: "BTC" },
1853
+ // "transaction_amount": { amount: "0.36775642", currency: "BTC" },
1854
+ // "confirmations": 15682
1855
+ // },
1856
+ // "to": {
1857
+ // "resource": "bitcoin_address",
1858
+ // "address": "1AHnhqbvbYx3rnZx8uC7NbFZaTe4tafFHX",
1859
+ // "currency": "BTC",
1860
+ // "address_info": { address: "1AHnhqbvbYx3rnZx8uC7NbFZaTe4tafFHX" }
1861
+ // },
1862
+ // "idem": "da0a2f14-a2af-4c5a-a37e-d4484caf582bsend",
1863
+ // "application": {
1864
+ // "id": "5756ab6e-836b-553b-8950-5e389451225d",
1865
+ // "resource": "application",
1866
+ // "resource_path": "/v2/applications/5756ab6e-836b-553b-8950-5e389451225d"
1867
+ // },
1868
+ // "details": { title: 'Sent Bitcoin', subtitle: "To Bitcoin address" }
1869
+ // }
1870
+ //
1871
+ // withdrawal transaction from coinbase to coinbasepro
1872
+ //
1873
+ // {
1874
+ // "id": "5b1b9fb8-5007-5393-b923-02903b973fdc",
1875
+ // "type": "pro_deposit",
1876
+ // "status": "completed",
1877
+ // "amount": { amount: "-0.00001111", currency: "BCH" },
1878
+ // "native_amount": { amount: "0.00", currency: "GBP" },
1879
+ // "description": null,
1880
+ // "created_at": "2019-02-28T13:31:58Z",
1881
+ // "updated_at": "2019-02-28T13:31:58Z",
1882
+ // "resource": "transaction",
1883
+ // "resource_path": "/v2/accounts/c01d7364-edd7-5f3a-bd1d-de53d4cbb25e/transactions/5b1b9fb8-5007-5393-b923-02903b973fdc",
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 Cash', subtitle: "To Coinbase Pro" }
1891
+ // }
1892
+ //
1893
+ // withdrawal transaction from coinbase to gdax
1894
+ //
1895
+ // {
1896
+ // "id": "badb7313-a9d3-5c07-abd0-00f8b44199b1",
1897
+ // "type": "exchange_deposit",
1898
+ // "status": "completed",
1899
+ // "amount": { amount: "-0.43704149", currency: "BCH" },
1900
+ // "native_amount": { amount: "-51.90", currency: "GBP" },
1901
+ // "description": null,
1902
+ // "created_at": "2019-03-19T10:30:40Z",
1903
+ // "updated_at": "2019-03-19T10:30:40Z",
1904
+ // "resource": "transaction",
1905
+ // "resource_path": "/v2/accounts/c01d7364-edd7-5f3a-bd1d-de53d4cbb25e/transactions/badb7313-a9d3-5c07-abd0-00f8b44199b1",
1906
+ // "instant_exchange": false,
1907
+ // "details": { title: 'Transferred Bitcoin Cash', subtitle: "To GDAX" }
1908
+ // }
1909
+ //
1910
+ // deposit transaction from gdax to coinbase
1911
+ //
1912
+ // {
1913
+ // "id": "9c4b642c-8688-58bf-8962-13cef64097de",
1914
+ // "type": "exchange_withdrawal",
1915
+ // "status": "completed",
1916
+ // "amount": { amount: "0.57729420", currency: "BTC" },
1917
+ // "native_amount": { amount: "4418.72", currency: "GBP" },
1918
+ // "description": null,
1919
+ // "created_at": "2018-02-17T11:33:33Z",
1920
+ // "updated_at": "2018-02-17T11:33:33Z",
1921
+ // "resource": "transaction",
1922
+ // "resource_path": "/v2/accounts/c6afbd34-4bd0-501e-8616-4862c193cd84/transactions/9c4b642c-8688-58bf-8962-13cef64097de",
1923
+ // "instant_exchange": false,
1924
+ // "details": { title: 'Transferred Bitcoin', subtitle: "From GDAX" }
1925
+ // }
1926
+ //
1927
+ // deposit transaction from coinbasepro to coinbase
1928
+ //
1929
+ // {
1930
+ // "id": "8d6dd0b9-3416-568a-889d-8f112fae9e81",
1931
+ // "type": "pro_withdrawal",
1932
+ // "status": "completed",
1933
+ // "amount": { amount: "0.40555386", currency: "BTC" },
1934
+ // "native_amount": { amount: "1140.27", currency: "GBP" },
1935
+ // "description": null,
1936
+ // "created_at": "2019-03-04T19:41:58Z",
1937
+ // "updated_at": "2019-03-04T19:41:58Z",
1938
+ // "resource": "transaction",
1939
+ // "resource_path": "/v2/accounts/c6afbd34-4bd0-501e-8616-4862c193cd84/transactions/8d6dd0b9-3416-568a-889d-8f112fae9e81",
1940
+ // "instant_exchange": false,
1941
+ // "application": {
1942
+ // "id": "5756ab6e-836b-553b-8950-5e389451225d",
1943
+ // "resource": "application",
1944
+ // "resource_path": "/v2/applications/5756ab6e-836b-553b-8950-5e389451225d"
1945
+ // },
1946
+ // "details": { title: 'Transferred Bitcoin', subtitle: "From Coinbase Pro" }
1947
+ // }
1948
+ //
1949
+ // sell trade
1950
+ //
1951
+ // {
1952
+ // "id": "a9409207-df64-585b-97ab-a50780d2149e",
1953
+ // "type": "sell",
1954
+ // "status": "completed",
1955
+ // "amount": { amount: "-9.09922880", currency: "BTC" },
1956
+ // "native_amount": { amount: "-7285.73", currency: "GBP" },
1957
+ // "description": null,
1958
+ // "created_at": "2017-03-27T15:38:34Z",
1959
+ // "updated_at": "2017-03-27T15:38:34Z",
1960
+ // "resource": "transaction",
1961
+ // "resource_path": "/v2/accounts/c6afbd34-4bd0-501e-8616-4862c193cd84/transactions/a9409207-df64-585b-97ab-a50780d2149e",
1962
+ // "instant_exchange": false,
1963
+ // "sell": {
1964
+ // "id": "e3550b4d-8ae6-5de3-95fe-1fb01ba83051",
1965
+ // "resource": "sell",
1966
+ // "resource_path": "/v2/accounts/c6afbd34-4bd0-501e-8616-4862c193cd84/sells/e3550b4d-8ae6-5de3-95fe-1fb01ba83051"
1967
+ // },
1968
+ // "details": {
1969
+ // "title": "Sold Bitcoin",
1970
+ // "subtitle": "Using EUR Wallet",
1971
+ // "payment_method_name": "EUR Wallet"
1972
+ // }
1973
+ // }
1974
+ //
1975
+ // buy trade
1976
+ //
1977
+ // {
1978
+ // "id": "63eeed67-9396-5912-86e9-73c4f10fe147",
1979
+ // "type": "buy",
1980
+ // "status": "completed",
1981
+ // "amount": { amount: "2.39605772", currency: "ETH" },
1982
+ // "native_amount": { amount: "98.31", currency: "GBP" },
1983
+ // "description": null,
1984
+ // "created_at": "2017-03-27T09:07:56Z",
1985
+ // "updated_at": "2017-03-27T09:07:57Z",
1986
+ // "resource": "transaction",
1987
+ // "resource_path": "/v2/accounts/8902f85d-4a69-5d74-82fe-8e390201bda7/transactions/63eeed67-9396-5912-86e9-73c4f10fe147",
1988
+ // "instant_exchange": false,
1989
+ // "buy": {
1990
+ // "id": "20b25b36-76c6-5353-aa57-b06a29a39d82",
1991
+ // "resource": "buy",
1992
+ // "resource_path": "/v2/accounts/8902f85d-4a69-5d74-82fe-8e390201bda7/buys/20b25b36-76c6-5353-aa57-b06a29a39d82"
1993
+ // },
1994
+ // "details": {
1995
+ // "title": "Bought Ethereum",
1996
+ // "subtitle": "Using EUR Wallet",
1997
+ // "payment_method_name": "EUR Wallet"
1998
+ // }
1999
+ // }
2000
+ //
2001
+ // fiat deposit transaction
2002
+ //
2003
+ // {
2004
+ // "id": "04ed4113-3732-5b0c-af86-b1d2146977d0",
2005
+ // "type": "fiat_deposit",
2006
+ // "status": "completed",
2007
+ // "amount": { amount: "114.02", currency: "EUR" },
2008
+ // "native_amount": { amount: "97.23", currency: "GBP" },
2009
+ // "description": null,
2010
+ // "created_at": "2017-02-09T07:01:21Z",
2011
+ // "updated_at": "2017-02-09T07:01:22Z",
2012
+ // "resource": "transaction",
2013
+ // "resource_path": "/v2/accounts/91cd2d36-3a91-55b6-a5d4-0124cf105483/transactions/04ed4113-3732-5b0c-af86-b1d2146977d0",
2014
+ // "instant_exchange": false,
2015
+ // "fiat_deposit": {
2016
+ // "id": "f34c19f3-b730-5e3d-9f72-96520448677a",
2017
+ // "resource": "fiat_deposit",
2018
+ // "resource_path": "/v2/accounts/91cd2d36-3a91-55b6-a5d4-0124cf105483/deposits/f34c19f3-b730-5e3d-9f72-96520448677a"
2019
+ // },
2020
+ // "details": {
2021
+ // "title": "Deposited funds",
2022
+ // "subtitle": "From SEPA Transfer (GB47 BARC 20..., reference CBADVI)",
2023
+ // "payment_method_name": "SEPA Transfer (GB47 BARC 20..., reference CBADVI)"
2024
+ // }
2025
+ // }
2026
+ //
2027
+ // fiat withdrawal transaction
2028
+ //
2029
+ // {
2030
+ // "id": "957d98e2-f80e-5e2f-a28e-02945aa93079",
2031
+ // "type": "fiat_withdrawal",
2032
+ // "status": "completed",
2033
+ // "amount": { amount: "-11000.00", currency: "EUR" },
2034
+ // "native_amount": { amount: "-9698.22", currency: "GBP" },
2035
+ // "description": null,
2036
+ // "created_at": "2017-12-06T13:19:19Z",
2037
+ // "updated_at": "2017-12-06T13:19:19Z",
2038
+ // "resource": "transaction",
2039
+ // "resource_path": "/v2/accounts/91cd2d36-3a91-55b6-a5d4-0124cf105483/transactions/957d98e2-f80e-5e2f-a28e-02945aa93079",
2040
+ // "instant_exchange": false,
2041
+ // "fiat_withdrawal": {
2042
+ // "id": "f4bf1fd9-ab3b-5de7-906d-ed3e23f7a4e7",
2043
+ // "resource": "fiat_withdrawal",
2044
+ // "resource_path": "/v2/accounts/91cd2d36-3a91-55b6-a5d4-0124cf105483/withdrawals/f4bf1fd9-ab3b-5de7-906d-ed3e23f7a4e7"
2045
+ // },
2046
+ // "details": {
2047
+ // "title": "Withdrew funds",
2048
+ // "subtitle": "To HSBC BANK PLC (GB74 MIDL...)",
2049
+ // "payment_method_name": "HSBC BANK PLC (GB74 MIDL...)"
2050
+ // }
2051
+ // }
2052
+ //
2053
+ const amountInfo = this.safeValue(item, 'amount', {});
2054
+ let amount = this.safeString(amountInfo, 'amount');
2055
+ let direction = undefined;
2056
+ if (Precise["default"].stringLt(amount, '0')) {
2057
+ direction = 'out';
2058
+ amount = Precise["default"].stringNeg(amount);
2059
+ }
2060
+ else {
2061
+ direction = 'in';
2062
+ }
2063
+ const currencyId = this.safeString(amountInfo, 'currency');
2064
+ const code = this.safeCurrencyCode(currencyId, currency);
2065
+ //
2066
+ // the address and txid do not belong to the unified ledger structure
2067
+ //
2068
+ // let address = undefined;
2069
+ // if (item['to']) {
2070
+ // address = this.safeString (item['to'], 'address');
2071
+ // }
2072
+ // let txid = undefined;
2073
+ //
2074
+ let fee = undefined;
2075
+ const networkInfo = this.safeValue(item, 'network', {});
2076
+ // txid = network['hash']; // txid does not belong to the unified ledger structure
2077
+ const feeInfo = this.safeValue(networkInfo, 'transaction_fee');
2078
+ if (feeInfo !== undefined) {
2079
+ const feeCurrencyId = this.safeString(feeInfo, 'currency');
2080
+ const feeCurrencyCode = this.safeCurrencyCode(feeCurrencyId, currency);
2081
+ const feeAmount = this.safeNumber(feeInfo, 'amount');
2082
+ fee = {
2083
+ 'cost': feeAmount,
2084
+ 'currency': feeCurrencyCode,
2085
+ };
2086
+ }
2087
+ const timestamp = this.parse8601(this.safeValue(item, 'created_at'));
2088
+ const id = this.safeString(item, 'id');
2089
+ const type = this.parseLedgerEntryType(this.safeString(item, 'type'));
2090
+ const status = this.parseLedgerEntryStatus(this.safeString(item, 'status'));
2091
+ const path = this.safeString(item, 'resource_path');
2092
+ let accountId = undefined;
2093
+ if (path !== undefined) {
2094
+ const parts = path.split('/');
2095
+ const numParts = parts.length;
2096
+ if (numParts > 3) {
2097
+ accountId = parts[3];
2098
+ }
2099
+ }
2100
+ return {
2101
+ 'info': item,
2102
+ 'id': id,
2103
+ 'timestamp': timestamp,
2104
+ 'datetime': this.iso8601(timestamp),
2105
+ 'direction': direction,
2106
+ 'account': accountId,
2107
+ 'referenceId': undefined,
2108
+ 'referenceAccount': undefined,
2109
+ 'type': type,
2110
+ 'currency': code,
2111
+ 'amount': this.parseNumber(amount),
2112
+ 'before': undefined,
2113
+ 'after': undefined,
2114
+ 'status': status,
2115
+ 'fee': fee,
2116
+ };
2117
+ }
2118
+ async findAccountId(code) {
2119
+ await this.loadMarkets();
2120
+ await this.loadAccounts();
2121
+ for (let i = 0; i < this.accounts.length; i++) {
2122
+ const account = this.accounts[i];
2123
+ if (account['code'] === code) {
2124
+ return account['id'];
2125
+ }
2126
+ }
2127
+ return undefined;
2128
+ }
2129
+ prepareAccountRequest(limit = undefined, params = {}) {
2130
+ const accountId = this.safeString2(params, 'account_id', 'accountId');
2131
+ if (accountId === undefined) {
2132
+ throw new errors.ArgumentsRequired(this.id + ' prepareAccountRequest() method requires an account_id (or accountId) parameter');
2133
+ }
2134
+ const request = {
2135
+ 'account_id': accountId,
2136
+ };
2137
+ if (limit !== undefined) {
2138
+ request['limit'] = limit;
2139
+ }
2140
+ return request;
2141
+ }
2142
+ async prepareAccountRequestWithCurrencyCode(code = undefined, limit = undefined, params = {}) {
2143
+ let accountId = this.safeString2(params, 'account_id', 'accountId');
2144
+ if (accountId === undefined) {
2145
+ if (code === undefined) {
2146
+ throw new errors.ArgumentsRequired(this.id + ' prepareAccountRequestWithCurrencyCode() method requires an account_id (or accountId) parameter OR a currency code argument');
2147
+ }
2148
+ accountId = await this.findAccountId(code);
2149
+ if (accountId === undefined) {
2150
+ throw new errors.ExchangeError(this.id + ' prepareAccountRequestWithCurrencyCode() could not find account id for ' + code);
2151
+ }
2152
+ }
2153
+ const request = {
2154
+ 'account_id': accountId,
2155
+ };
2156
+ if (limit !== undefined) {
2157
+ request['limit'] = limit;
2158
+ }
2159
+ return request;
2160
+ }
2161
+ async createMarketBuyOrderWithCost(symbol, cost, params = {}) {
2162
+ /**
2163
+ * @method
2164
+ * @name coinbase#createMarketBuyOrderWithCost
2165
+ * @description create a market buy order by providing the symbol and cost
2166
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_postorder
2167
+ * @param {string} symbol unified symbol of the market to create an order in
2168
+ * @param {float} cost how much you want to trade in units of the quote currency
2169
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2170
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2171
+ */
2172
+ await this.loadMarkets();
2173
+ const market = this.market(symbol);
2174
+ if (!market['spot']) {
2175
+ throw new errors.NotSupported(this.id + ' createMarketBuyOrderWithCost() supports spot orders only');
2176
+ }
2177
+ params['createMarketBuyOrderRequiresPrice'] = false;
2178
+ return await this.createOrder(symbol, 'market', 'buy', cost, undefined, params);
2179
+ }
2180
+ async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
2181
+ /**
2182
+ * @method
2183
+ * @name coinbase#createOrder
2184
+ * @description create a trade order
2185
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_postorder
2186
+ * @param {string} symbol unified symbol of the market to create an order in
2187
+ * @param {string} type 'market' or 'limit'
2188
+ * @param {string} side 'buy' or 'sell'
2189
+ * @param {float} amount how much you want to trade in units of the base currency, quote currency for 'market' 'buy' orders
2190
+ * @param {float} [price] the price to fulfill the order, in units of the quote currency, ignored in market orders
2191
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2192
+ * @param {float} [params.stopPrice] price to trigger stop orders
2193
+ * @param {float} [params.triggerPrice] price to trigger stop orders
2194
+ * @param {float} [params.stopLossPrice] price to trigger stop-loss orders
2195
+ * @param {float} [params.takeProfitPrice] price to trigger take-profit orders
2196
+ * @param {bool} [params.postOnly] true or false
2197
+ * @param {string} [params.timeInForce] 'GTC', 'IOC', 'GTD' or 'PO'
2198
+ * @param {string} [params.stop_direction] 'UNKNOWN_STOP_DIRECTION', 'STOP_DIRECTION_STOP_UP', 'STOP_DIRECTION_STOP_DOWN' the direction the stopPrice is triggered from
2199
+ * @param {string} [params.end_time] '2023-05-25T17:01:05.092Z' for 'GTD' orders
2200
+ * @param {float} [params.cost] *spot market buy only* the quote quantity that can be used as an alternative for the amount
2201
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2202
+ */
2203
+ await this.loadMarkets();
2204
+ const market = this.market(symbol);
2205
+ const request = {
2206
+ 'client_order_id': this.uuid(),
2207
+ 'product_id': market['id'],
2208
+ 'side': side.toUpperCase(),
2209
+ };
2210
+ const stopPrice = this.safeNumberN(params, ['stopPrice', 'stop_price', 'triggerPrice']);
2211
+ const stopLossPrice = this.safeNumber(params, 'stopLossPrice');
2212
+ const takeProfitPrice = this.safeNumber(params, 'takeProfitPrice');
2213
+ const isStop = stopPrice !== undefined;
2214
+ const isStopLoss = stopLossPrice !== undefined;
2215
+ const isTakeProfit = takeProfitPrice !== undefined;
2216
+ const timeInForce = this.safeString(params, 'timeInForce');
2217
+ const postOnly = (timeInForce === 'PO') ? true : this.safeValue2(params, 'postOnly', 'post_only', false);
2218
+ const endTime = this.safeString(params, 'end_time');
2219
+ let stopDirection = this.safeString(params, 'stop_direction');
2220
+ if (type === 'limit') {
2221
+ if (isStop) {
2222
+ if (stopDirection === undefined) {
2223
+ stopDirection = (side === 'buy') ? 'STOP_DIRECTION_STOP_DOWN' : 'STOP_DIRECTION_STOP_UP';
2224
+ }
2225
+ if ((timeInForce === 'GTD') || (endTime !== undefined)) {
2226
+ if (endTime === undefined) {
2227
+ throw new errors.ExchangeError(this.id + ' createOrder() requires an end_time parameter for a GTD order');
2228
+ }
2229
+ request['order_configuration'] = {
2230
+ 'stop_limit_stop_limit_gtd': {
2231
+ 'base_size': this.amountToPrecision(symbol, amount),
2232
+ 'limit_price': this.priceToPrecision(symbol, price),
2233
+ 'stop_price': this.priceToPrecision(symbol, stopPrice),
2234
+ 'stop_direction': stopDirection,
2235
+ 'end_time': endTime,
2236
+ },
2237
+ };
2238
+ }
2239
+ else {
2240
+ request['order_configuration'] = {
2241
+ 'stop_limit_stop_limit_gtc': {
2242
+ 'base_size': this.amountToPrecision(symbol, amount),
2243
+ 'limit_price': this.priceToPrecision(symbol, price),
2244
+ 'stop_price': this.priceToPrecision(symbol, stopPrice),
2245
+ 'stop_direction': stopDirection,
2246
+ },
2247
+ };
2248
+ }
2249
+ }
2250
+ else if (isStopLoss || isTakeProfit) {
2251
+ let triggerPrice = undefined;
2252
+ if (isStopLoss) {
2253
+ if (stopDirection === undefined) {
2254
+ stopDirection = (side === 'buy') ? 'STOP_DIRECTION_STOP_UP' : 'STOP_DIRECTION_STOP_DOWN';
2255
+ }
2256
+ triggerPrice = this.priceToPrecision(symbol, stopLossPrice);
2257
+ }
2258
+ else {
2259
+ if (stopDirection === undefined) {
2260
+ stopDirection = (side === 'buy') ? 'STOP_DIRECTION_STOP_DOWN' : 'STOP_DIRECTION_STOP_UP';
2261
+ }
2262
+ triggerPrice = this.priceToPrecision(symbol, takeProfitPrice);
2263
+ }
2264
+ request['order_configuration'] = {
2265
+ 'stop_limit_stop_limit_gtc': {
2266
+ 'base_size': this.amountToPrecision(symbol, amount),
2267
+ 'limit_price': this.priceToPrecision(symbol, price),
2268
+ 'stop_price': triggerPrice,
2269
+ 'stop_direction': stopDirection,
2270
+ },
2271
+ };
2272
+ }
2273
+ else {
2274
+ if ((timeInForce === 'GTD') || (endTime !== undefined)) {
2275
+ if (endTime === undefined) {
2276
+ throw new errors.ExchangeError(this.id + ' createOrder() requires an end_time parameter for a GTD order');
2277
+ }
2278
+ request['order_configuration'] = {
2279
+ 'limit_limit_gtd': {
2280
+ 'base_size': this.amountToPrecision(symbol, amount),
2281
+ 'limit_price': this.priceToPrecision(symbol, price),
2282
+ 'end_time': endTime,
2283
+ 'post_only': postOnly,
2284
+ },
2285
+ };
2286
+ }
2287
+ else {
2288
+ request['order_configuration'] = {
2289
+ 'limit_limit_gtc': {
2290
+ 'base_size': this.amountToPrecision(symbol, amount),
2291
+ 'limit_price': this.priceToPrecision(symbol, price),
2292
+ 'post_only': postOnly,
2293
+ },
2294
+ };
2295
+ }
2296
+ }
2297
+ }
2298
+ else {
2299
+ if (isStop || isStopLoss || isTakeProfit) {
2300
+ throw new errors.NotSupported(this.id + ' createOrder() only stop limit orders are supported');
2301
+ }
2302
+ if (side === 'buy') {
2303
+ let total = undefined;
2304
+ let createMarketBuyOrderRequiresPrice = true;
2305
+ [createMarketBuyOrderRequiresPrice, params] = this.handleOptionAndParams(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', true);
2306
+ const cost = this.safeNumber(params, 'cost');
2307
+ params = this.omit(params, 'cost');
2308
+ if (cost !== undefined) {
2309
+ total = this.costToPrecision(symbol, cost);
2310
+ }
2311
+ else if (createMarketBuyOrderRequiresPrice) {
2312
+ if (price === undefined) {
2313
+ 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');
2314
+ }
2315
+ else {
2316
+ const amountString = this.numberToString(amount);
2317
+ const priceString = this.numberToString(price);
2318
+ const costRequest = Precise["default"].stringMul(amountString, priceString);
2319
+ total = this.costToPrecision(symbol, costRequest);
2320
+ }
2321
+ }
2322
+ else {
2323
+ total = this.costToPrecision(symbol, amount);
2324
+ }
2325
+ request['order_configuration'] = {
2326
+ 'market_market_ioc': {
2327
+ 'quote_size': total,
2328
+ },
2329
+ };
2330
+ }
2331
+ else {
2332
+ request['order_configuration'] = {
2333
+ 'market_market_ioc': {
2334
+ 'base_size': this.amountToPrecision(symbol, amount),
2335
+ },
2336
+ };
2337
+ }
2338
+ }
2339
+ params = this.omit(params, ['timeInForce', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'stop_price', 'stopDirection', 'stop_direction', 'clientOrderId', 'postOnly', 'post_only', 'end_time']);
2340
+ const response = await this.v3PrivatePostBrokerageOrders(this.extend(request, params));
2341
+ //
2342
+ // successful order
2343
+ //
2344
+ // {
2345
+ // "success": true,
2346
+ // "failure_reason": "UNKNOWN_FAILURE_REASON",
2347
+ // "order_id": "52cfe5e2-0b29-4c19-a245-a6a773de5030",
2348
+ // "success_response": {
2349
+ // "order_id": "52cfe5e2-0b29-4c19-a245-a6a773de5030",
2350
+ // "product_id": "LTC-BTC",
2351
+ // "side": "SELL",
2352
+ // "client_order_id": "4d760580-6fca-4094-a70b-ebcca8626288"
2353
+ // },
2354
+ // "order_configuration": null
2355
+ // }
2356
+ //
2357
+ // failed order
2358
+ //
2359
+ // {
2360
+ // "success": false,
2361
+ // "failure_reason": "UNKNOWN_FAILURE_REASON",
2362
+ // "order_id": "",
2363
+ // "error_response": {
2364
+ // "error": "UNSUPPORTED_ORDER_CONFIGURATION",
2365
+ // "message": "source is not enabled for trading",
2366
+ // "error_details": "",
2367
+ // "new_order_failure_reason": "UNSUPPORTED_ORDER_CONFIGURATION"
2368
+ // },
2369
+ // "order_configuration": {
2370
+ // "limit_limit_gtc": {
2371
+ // "base_size": "100",
2372
+ // "limit_price": "40000",
2373
+ // "post_only": false
2374
+ // }
2375
+ // }
2376
+ // }
2377
+ //
2378
+ const success = this.safeValue(response, 'success');
2379
+ if (success !== true) {
2380
+ const errorResponse = this.safeValue(response, 'error_response');
2381
+ const errorTitle = this.safeString(errorResponse, 'error');
2382
+ const errorMessage = this.safeString(errorResponse, 'message');
2383
+ if (errorResponse !== undefined) {
2384
+ this.throwExactlyMatchedException(this.exceptions['exact'], errorTitle, errorMessage);
2385
+ this.throwBroadlyMatchedException(this.exceptions['broad'], errorTitle, errorMessage);
2386
+ throw new errors.ExchangeError(errorMessage);
2387
+ }
2388
+ }
2389
+ const data = this.safeValue(response, 'success_response', {});
2390
+ return this.parseOrder(data, market);
2391
+ }
2392
+ parseOrder(order, market = undefined) {
2393
+ //
2394
+ // createOrder
2395
+ //
2396
+ // {
2397
+ // "order_id": "52cfe5e2-0b29-4c19-a245-a6a773de5030",
2398
+ // "product_id": "LTC-BTC",
2399
+ // "side": "SELL",
2400
+ // "client_order_id": "4d760580-6fca-4094-a70b-ebcca8626288"
2401
+ // }
2402
+ //
2403
+ // cancelOrder, cancelOrders
2404
+ //
2405
+ // {
2406
+ // "success": true,
2407
+ // "failure_reason": "UNKNOWN_CANCEL_FAILURE_REASON",
2408
+ // "order_id": "bb8851a3-4fda-4a2c-aa06-9048db0e0f0d"
2409
+ // }
2410
+ //
2411
+ // fetchOrder, fetchOrders, fetchOpenOrders, fetchClosedOrders, fetchCanceledOrders
2412
+ //
2413
+ // {
2414
+ // "order_id": "9bc1eb3b-5b46-4b71-9628-ae2ed0cca75b",
2415
+ // "product_id": "LTC-BTC",
2416
+ // "user_id": "1111111-1111-1111-1111-111111111111",
2417
+ // "order_configuration": {
2418
+ // "limit_limit_gtc": {
2419
+ // "base_size": "0.2",
2420
+ // "limit_price": "0.006",
2421
+ // "post_only": false
2422
+ // },
2423
+ // "stop_limit_stop_limit_gtc": {
2424
+ // "base_size": "48.54",
2425
+ // "limit_price": "6.998",
2426
+ // "stop_price": "7.0687",
2427
+ // "stop_direction": "STOP_DIRECTION_STOP_DOWN"
2428
+ // }
2429
+ // },
2430
+ // "side": "SELL",
2431
+ // "client_order_id": "e5fe8482-05bb-428f-ad4d-dbc8ce39239c",
2432
+ // "status": "OPEN",
2433
+ // "time_in_force": "GOOD_UNTIL_CANCELLED",
2434
+ // "created_time": "2023-01-16T23:37:23.947030Z",
2435
+ // "completion_percentage": "0",
2436
+ // "filled_size": "0",
2437
+ // "average_filled_price": "0",
2438
+ // "fee": "",
2439
+ // "number_of_fills": "0",
2440
+ // "filled_value": "0",
2441
+ // "pending_cancel": false,
2442
+ // "size_in_quote": false,
2443
+ // "total_fees": "0",
2444
+ // "size_inclusive_of_fees": false,
2445
+ // "total_value_after_fees": "0",
2446
+ // "trigger_status": "INVALID_ORDER_TYPE",
2447
+ // "order_type": "LIMIT",
2448
+ // "reject_reason": "REJECT_REASON_UNSPECIFIED",
2449
+ // "settled": false,
2450
+ // "product_type": "SPOT",
2451
+ // "reject_message": "",
2452
+ // "cancel_message": ""
2453
+ // }
2454
+ //
2455
+ const marketId = this.safeString(order, 'product_id');
2456
+ const symbol = this.safeSymbol(marketId, market, '-');
2457
+ if (symbol !== undefined) {
2458
+ market = this.market(symbol);
2459
+ }
2460
+ const orderConfiguration = this.safeValue(order, 'order_configuration', {});
2461
+ const limitGTC = this.safeValue(orderConfiguration, 'limit_limit_gtc');
2462
+ const limitGTD = this.safeValue(orderConfiguration, 'limit_limit_gtd');
2463
+ const stopLimitGTC = this.safeValue(orderConfiguration, 'stop_limit_stop_limit_gtc');
2464
+ const stopLimitGTD = this.safeValue(orderConfiguration, 'stop_limit_stop_limit_gtd');
2465
+ const marketIOC = this.safeValue(orderConfiguration, 'market_market_ioc');
2466
+ const isLimit = ((limitGTC !== undefined) || (limitGTD !== undefined));
2467
+ const isStop = ((stopLimitGTC !== undefined) || (stopLimitGTD !== undefined));
2468
+ let price = undefined;
2469
+ let amount = undefined;
2470
+ let postOnly = undefined;
2471
+ let triggerPrice = undefined;
2472
+ if (isLimit) {
2473
+ const target = (limitGTC !== undefined) ? limitGTC : limitGTD;
2474
+ price = this.safeString(target, 'limit_price');
2475
+ amount = this.safeString(target, 'base_size');
2476
+ postOnly = this.safeValue(target, 'post_only');
2477
+ }
2478
+ else if (isStop) {
2479
+ const stopTarget = (stopLimitGTC !== undefined) ? stopLimitGTC : stopLimitGTD;
2480
+ price = this.safeString(stopTarget, 'limit_price');
2481
+ amount = this.safeString(stopTarget, 'base_size');
2482
+ postOnly = this.safeValue(stopTarget, 'post_only');
2483
+ triggerPrice = this.safeString(stopTarget, 'stop_price');
2484
+ }
2485
+ else {
2486
+ amount = this.safeString(marketIOC, 'base_size');
2487
+ }
2488
+ const datetime = this.safeString(order, 'created_time');
2489
+ const totalFees = this.safeString(order, 'total_fees');
2490
+ let currencyFee = undefined;
2491
+ if ((totalFees !== undefined) && (market !== undefined)) {
2492
+ currencyFee = market['quote'];
2493
+ }
2494
+ return this.safeOrder({
2495
+ 'info': order,
2496
+ 'id': this.safeString(order, 'order_id'),
2497
+ 'clientOrderId': this.safeString(order, 'client_order_id'),
2498
+ 'timestamp': this.parse8601(datetime),
2499
+ 'datetime': datetime,
2500
+ 'lastTradeTimestamp': undefined,
2501
+ 'symbol': symbol,
2502
+ 'type': this.parseOrderType(this.safeString(order, 'order_type')),
2503
+ 'timeInForce': this.parseTimeInForce(this.safeString(order, 'time_in_force')),
2504
+ 'postOnly': postOnly,
2505
+ 'side': this.safeStringLower(order, 'side'),
2506
+ 'price': price,
2507
+ 'stopPrice': triggerPrice,
2508
+ 'triggerPrice': triggerPrice,
2509
+ 'amount': amount,
2510
+ 'filled': this.safeString(order, 'filled_size'),
2511
+ 'remaining': undefined,
2512
+ 'cost': undefined,
2513
+ 'average': this.safeString(order, 'average_filled_price'),
2514
+ 'status': this.parseOrderStatus(this.safeString(order, 'status')),
2515
+ 'fee': {
2516
+ 'cost': this.safeString(order, 'total_fees'),
2517
+ 'currency': currencyFee,
2518
+ },
2519
+ 'trades': undefined,
2520
+ }, market);
2521
+ }
2522
+ parseOrderStatus(status) {
2523
+ const statuses = {
2524
+ 'OPEN': 'open',
2525
+ 'FILLED': 'closed',
2526
+ 'CANCELLED': 'canceled',
2527
+ 'EXPIRED': 'canceled',
2528
+ 'FAILED': 'canceled',
2529
+ 'UNKNOWN_ORDER_STATUS': undefined,
2530
+ };
2531
+ return this.safeString(statuses, status, status);
2532
+ }
2533
+ parseOrderType(type) {
2534
+ if (type === 'UNKNOWN_ORDER_TYPE') {
2535
+ return undefined;
2536
+ }
2537
+ const types = {
2538
+ 'MARKET': 'market',
2539
+ 'LIMIT': 'limit',
2540
+ 'STOP': 'limit',
2541
+ 'STOP_LIMIT': 'limit',
2542
+ };
2543
+ return this.safeString(types, type, type);
2544
+ }
2545
+ parseTimeInForce(timeInForce) {
2546
+ const timeInForces = {
2547
+ 'GOOD_UNTIL_CANCELLED': 'GTC',
2548
+ 'GOOD_UNTIL_DATE_TIME': 'GTD',
2549
+ 'IMMEDIATE_OR_CANCEL': 'IOC',
2550
+ 'FILL_OR_KILL': 'FOK',
2551
+ 'UNKNOWN_TIME_IN_FORCE': undefined,
2552
+ };
2553
+ return this.safeString(timeInForces, timeInForce, timeInForce);
2554
+ }
2555
+ async cancelOrder(id, symbol = undefined, params = {}) {
2556
+ /**
2557
+ * @method
2558
+ * @name coinbase#cancelOrder
2559
+ * @description cancels an open order
2560
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_cancelorders
2561
+ * @param {string} id order id
2562
+ * @param {string} symbol not used by coinbase cancelOrder()
2563
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2564
+ * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2565
+ */
2566
+ await this.loadMarkets();
2567
+ const orders = await this.cancelOrders([id], symbol, params);
2568
+ return this.safeValue(orders, 0, {});
2569
+ }
2570
+ async cancelOrders(ids, symbol = undefined, params = {}) {
2571
+ /**
2572
+ * @method
2573
+ * @name coinbase#cancelOrders
2574
+ * @description cancel multiple orders
2575
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_cancelorders
2576
+ * @param {string[]} ids order ids
2577
+ * @param {string} symbol not used by coinbase cancelOrders()
2578
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2579
+ * @returns {object} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2580
+ */
2581
+ await this.loadMarkets();
2582
+ let market = undefined;
2583
+ if (symbol !== undefined) {
2584
+ market = this.market(symbol);
2585
+ }
2586
+ const request = {
2587
+ 'order_ids': ids,
2588
+ };
2589
+ const response = await this.v3PrivatePostBrokerageOrdersBatchCancel(this.extend(request, params));
2590
+ //
2591
+ // {
2592
+ // "results": [
2593
+ // {
2594
+ // "success": true,
2595
+ // "failure_reason": "UNKNOWN_CANCEL_FAILURE_REASON",
2596
+ // "order_id": "bb8851a3-4fda-4a2c-aa06-9048db0e0f0d"
2597
+ // }
2598
+ // ]
2599
+ // }
2600
+ //
2601
+ const orders = this.safeValue(response, 'results', []);
2602
+ for (let i = 0; i < orders.length; i++) {
2603
+ const success = this.safeValue(orders[i], 'success');
2604
+ if (success !== true) {
2605
+ throw new errors.BadRequest(this.id + ' cancelOrders() has failed, check your arguments and parameters');
2606
+ }
2607
+ }
2608
+ return this.parseOrders(orders, market);
2609
+ }
2610
+ async editOrder(id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
2611
+ /**
2612
+ * @method
2613
+ * @name coinbase#editOrder
2614
+ * @description edit a trade order
2615
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_editorder
2616
+ * @param {string} id cancel order id
2617
+ * @param {string} symbol unified symbol of the market to create an order in
2618
+ * @param {string} type 'market' or 'limit'
2619
+ * @param {string} side 'buy' or 'sell'
2620
+ * @param {float} amount how much of currency you want to trade in units of base currency
2621
+ * @param {float} [price] the price at which the order is to be fullfilled, in units of the base currency, ignored in market orders
2622
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2623
+ * @param {boolean} [params.preview] default to false, wether to use the test/preview endpoint or not
2624
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2625
+ */
2626
+ await this.loadMarkets();
2627
+ const market = this.market(symbol);
2628
+ const request = {
2629
+ 'order_id': id,
2630
+ };
2631
+ if (amount !== undefined) {
2632
+ request['size'] = this.amountToPrecision(symbol, amount);
2633
+ }
2634
+ if (price !== undefined) {
2635
+ request['price'] = this.priceToPrecision(symbol, price);
2636
+ }
2637
+ const preview = this.safeValue2(params, 'preview', 'test', false);
2638
+ let response = undefined;
2639
+ if (preview) {
2640
+ params = this.omit(params, ['preview', 'test']);
2641
+ response = await this.v3PrivatePostBrokerageOrdersEditPreview(this.extend(request, params));
2642
+ }
2643
+ else {
2644
+ response = await this.v3PrivatePostBrokerageOrdersEdit(this.extend(request, params));
2645
+ }
2646
+ //
2647
+ // {
2648
+ // "success": true,
2649
+ // "errors": {
2650
+ // "edit_failure_reason": "UNKNOWN_EDIT_ORDER_FAILURE_REASON",
2651
+ // "preview_failure_reason": "UNKNOWN_PREVIEW_FAILURE_REASON"
2652
+ // }
2653
+ // }
2654
+ //
2655
+ return this.parseOrder(response, market);
2656
+ }
2657
+ async fetchOrder(id, symbol = undefined, params = {}) {
2658
+ /**
2659
+ * @method
2660
+ * @name coinbase#fetchOrder
2661
+ * @description fetches information on an order made by the user
2662
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_gethistoricalorder
2663
+ * @param {string} id the order id
2664
+ * @param {string} symbol unified market symbol that the order was made in
2665
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2666
+ * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2667
+ */
2668
+ await this.loadMarkets();
2669
+ let market = undefined;
2670
+ if (symbol !== undefined) {
2671
+ market = this.market(symbol);
2672
+ }
2673
+ const request = {
2674
+ 'order_id': id,
2675
+ };
2676
+ const response = await this.v3PrivateGetBrokerageOrdersHistoricalOrderId(this.extend(request, params));
2677
+ //
2678
+ // {
2679
+ // "order": {
2680
+ // "order_id": "9bc1eb3b-5b46-4b71-9628-ae2ed0cca75b",
2681
+ // "product_id": "LTC-BTC",
2682
+ // "user_id": "1111111-1111-1111-1111-111111111111",
2683
+ // "order_configuration": {
2684
+ // "limit_limit_gtc": {
2685
+ // "base_size": "0.2",
2686
+ // "limit_price": "0.006",
2687
+ // "post_only": false
2688
+ // }
2689
+ // },
2690
+ // "side": "SELL",
2691
+ // "client_order_id": "e5fe8482-05bb-428f-ad4d-dbc8ce39239c",
2692
+ // "status": "OPEN",
2693
+ // "time_in_force": "GOOD_UNTIL_CANCELLED",
2694
+ // "created_time": "2023-01-16T23:37:23.947030Z",
2695
+ // "completion_percentage": "0",
2696
+ // "filled_size": "0",
2697
+ // "average_filled_price": "0",
2698
+ // "fee": "",
2699
+ // "number_of_fills": "0",
2700
+ // "filled_value": "0",
2701
+ // "pending_cancel": false,
2702
+ // "size_in_quote": false,
2703
+ // "total_fees": "0",
2704
+ // "size_inclusive_of_fees": false,
2705
+ // "total_value_after_fees": "0",
2706
+ // "trigger_status": "INVALID_ORDER_TYPE",
2707
+ // "order_type": "LIMIT",
2708
+ // "reject_reason": "REJECT_REASON_UNSPECIFIED",
2709
+ // "settled": false,
2710
+ // "product_type": "SPOT",
2711
+ // "reject_message": "",
2712
+ // "cancel_message": ""
2713
+ // }
2714
+ // }
2715
+ //
2716
+ const order = this.safeValue(response, 'order', {});
2717
+ return this.parseOrder(order, market);
2718
+ }
2719
+ async fetchOrders(symbol = undefined, since = undefined, limit = 100, params = {}) {
2720
+ /**
2721
+ * @method
2722
+ * @name coinbase#fetchOrders
2723
+ * @description fetches information on multiple orders made by the user
2724
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_gethistoricalorders
2725
+ * @param {string} symbol unified market symbol that the orders were made in
2726
+ * @param {int} [since] the earliest time in ms to fetch orders
2727
+ * @param {int} [limit] the maximum number of order structures to retrieve
2728
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2729
+ * @param {int} [params.until] the latest time in ms to fetch trades for
2730
+ * @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)
2731
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2732
+ */
2733
+ await this.loadMarkets();
2734
+ let paginate = false;
2735
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchOrders', 'paginate');
2736
+ if (paginate) {
2737
+ return await this.fetchPaginatedCallCursor('fetchOrders', symbol, since, limit, params, 'cursor', 'cursor', undefined, 100);
2738
+ }
2739
+ let market = undefined;
2740
+ if (symbol !== undefined) {
2741
+ market = this.market(symbol);
2742
+ }
2743
+ const request = {};
2744
+ if (market !== undefined) {
2745
+ request['product_id'] = market['id'];
2746
+ }
2747
+ if (limit !== undefined) {
2748
+ request['limit'] = limit;
2749
+ }
2750
+ if (since !== undefined) {
2751
+ request['start_date'] = this.iso8601(since);
2752
+ }
2753
+ const until = this.safeValueN(params, ['until', 'till']);
2754
+ if (until !== undefined) {
2755
+ params = this.omit(params, ['until', 'till']);
2756
+ request['end_date'] = this.iso8601(until);
2757
+ }
2758
+ const response = await this.v3PrivateGetBrokerageOrdersHistoricalBatch(this.extend(request, params));
2759
+ //
2760
+ // {
2761
+ // "orders": [
2762
+ // {
2763
+ // "order_id": "813a53c5-3e39-47bb-863d-2faf685d22d8",
2764
+ // "product_id": "BTC-USDT",
2765
+ // "user_id": "1111111-1111-1111-1111-111111111111",
2766
+ // "order_configuration": {
2767
+ // "market_market_ioc": {
2768
+ // "quote_size": "6.36"
2769
+ // }
2770
+ // },
2771
+ // "side": "BUY",
2772
+ // "client_order_id": "18eb9947-db49-4874-8e7b-39b8fe5f4317",
2773
+ // "status": "FILLED",
2774
+ // "time_in_force": "IMMEDIATE_OR_CANCEL",
2775
+ // "created_time": "2023-01-18T01:37:37.975552Z",
2776
+ // "completion_percentage": "100",
2777
+ // "filled_size": "0.000297920684505",
2778
+ // "average_filled_price": "21220.6399999973697697",
2779
+ // "fee": "",
2780
+ // "number_of_fills": "2",
2781
+ // "filled_value": "6.3220675944333996",
2782
+ // "pending_cancel": false,
2783
+ // "size_in_quote": true,
2784
+ // "total_fees": "0.0379324055666004",
2785
+ // "size_inclusive_of_fees": true,
2786
+ // "total_value_after_fees": "6.36",
2787
+ // "trigger_status": "INVALID_ORDER_TYPE",
2788
+ // "order_type": "MARKET",
2789
+ // "reject_reason": "REJECT_REASON_UNSPECIFIED",
2790
+ // "settled": true,
2791
+ // "product_type": "SPOT",
2792
+ // "reject_message": "",
2793
+ // "cancel_message": "Internal error"
2794
+ // },
2795
+ // ],
2796
+ // "sequence": "0",
2797
+ // "has_next": false,
2798
+ // "cursor": ""
2799
+ // }
2800
+ //
2801
+ const orders = this.safeValue(response, 'orders', []);
2802
+ const first = this.safeValue(orders, 0);
2803
+ const cursor = this.safeString(response, 'cursor');
2804
+ if ((cursor !== undefined) && (cursor !== '')) {
2805
+ first['cursor'] = cursor;
2806
+ orders[0] = first;
2807
+ }
2808
+ return this.parseOrders(orders, market, since, limit);
2809
+ }
2810
+ async fetchOrdersByStatus(status, symbol = undefined, since = undefined, limit = undefined, params = {}) {
2811
+ await this.loadMarkets();
2812
+ let market = undefined;
2813
+ if (symbol !== undefined) {
2814
+ market = this.market(symbol);
2815
+ }
2816
+ const request = {
2817
+ 'order_status': status,
2818
+ };
2819
+ if (market !== undefined) {
2820
+ request['product_id'] = market['id'];
2821
+ }
2822
+ if (limit === undefined) {
2823
+ limit = 100;
2824
+ }
2825
+ request['limit'] = limit;
2826
+ if (since !== undefined) {
2827
+ request['start_date'] = this.iso8601(since);
2828
+ }
2829
+ const until = this.safeValueN(params, ['until', 'till']);
2830
+ if (until !== undefined) {
2831
+ params = this.omit(params, ['until', 'till']);
2832
+ request['end_date'] = this.iso8601(until);
2833
+ }
2834
+ const response = await this.v3PrivateGetBrokerageOrdersHistoricalBatch(this.extend(request, params));
2835
+ //
2836
+ // {
2837
+ // "orders": [
2838
+ // {
2839
+ // "order_id": "813a53c5-3e39-47bb-863d-2faf685d22d8",
2840
+ // "product_id": "BTC-USDT",
2841
+ // "user_id": "1111111-1111-1111-1111-111111111111",
2842
+ // "order_configuration": {
2843
+ // "market_market_ioc": {
2844
+ // "quote_size": "6.36"
2845
+ // }
2846
+ // },
2847
+ // "side": "BUY",
2848
+ // "client_order_id": "18eb9947-db49-4874-8e7b-39b8fe5f4317",
2849
+ // "status": "FILLED",
2850
+ // "time_in_force": "IMMEDIATE_OR_CANCEL",
2851
+ // "created_time": "2023-01-18T01:37:37.975552Z",
2852
+ // "completion_percentage": "100",
2853
+ // "filled_size": "0.000297920684505",
2854
+ // "average_filled_price": "21220.6399999973697697",
2855
+ // "fee": "",
2856
+ // "number_of_fills": "2",
2857
+ // "filled_value": "6.3220675944333996",
2858
+ // "pending_cancel": false,
2859
+ // "size_in_quote": true,
2860
+ // "total_fees": "0.0379324055666004",
2861
+ // "size_inclusive_of_fees": true,
2862
+ // "total_value_after_fees": "6.36",
2863
+ // "trigger_status": "INVALID_ORDER_TYPE",
2864
+ // "order_type": "MARKET",
2865
+ // "reject_reason": "REJECT_REASON_UNSPECIFIED",
2866
+ // "settled": true,
2867
+ // "product_type": "SPOT",
2868
+ // "reject_message": "",
2869
+ // "cancel_message": "Internal error"
2870
+ // },
2871
+ // ],
2872
+ // "sequence": "0",
2873
+ // "has_next": false,
2874
+ // "cursor": ""
2875
+ // }
2876
+ //
2877
+ const orders = this.safeValue(response, 'orders', []);
2878
+ const first = this.safeValue(orders, 0);
2879
+ const cursor = this.safeString(response, 'cursor');
2880
+ if ((cursor !== undefined) && (cursor !== '')) {
2881
+ first['cursor'] = cursor;
2882
+ orders[0] = first;
2883
+ }
2884
+ return this.parseOrders(orders, market, since, limit);
2885
+ }
2886
+ async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
2887
+ /**
2888
+ * @method
2889
+ * @name coinbase#fetchOpenOrders
2890
+ * @description fetches information on all currently open orders
2891
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_gethistoricalorders
2892
+ * @param {string} symbol unified market symbol of the orders
2893
+ * @param {int} [since] timestamp in ms of the earliest order, default is undefined
2894
+ * @param {int} [limit] the maximum number of open order structures to retrieve
2895
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2896
+ * @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)
2897
+ * @param {int} [params.until] the latest time in ms to fetch trades for
2898
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2899
+ */
2900
+ await this.loadMarkets();
2901
+ let paginate = false;
2902
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchOpenOrders', 'paginate');
2903
+ if (paginate) {
2904
+ return await this.fetchPaginatedCallCursor('fetchOpenOrders', symbol, since, limit, params, 'cursor', 'cursor', undefined, 100);
2905
+ }
2906
+ return await this.fetchOrdersByStatus('OPEN', symbol, since, limit, params);
2907
+ }
2908
+ async fetchClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
2909
+ /**
2910
+ * @method
2911
+ * @name coinbase#fetchClosedOrders
2912
+ * @description fetches information on multiple closed orders made by the user
2913
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_gethistoricalorders
2914
+ * @param {string} symbol unified market symbol of the orders
2915
+ * @param {int} [since] timestamp in ms of the earliest order, default is undefined
2916
+ * @param {int} [limit] the maximum number of closed order structures to retrieve
2917
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2918
+ * @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)
2919
+ * @param {int} [params.until] the latest time in ms to fetch trades for
2920
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2921
+ */
2922
+ await this.loadMarkets();
2923
+ let paginate = false;
2924
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchClosedOrders', 'paginate');
2925
+ if (paginate) {
2926
+ return await this.fetchPaginatedCallCursor('fetchClosedOrders', symbol, since, limit, params, 'cursor', 'cursor', undefined, 100);
2927
+ }
2928
+ return await this.fetchOrdersByStatus('FILLED', symbol, since, limit, params);
2929
+ }
2930
+ async fetchCanceledOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
2931
+ /**
2932
+ * @method
2933
+ * @name coinbase#fetchCanceledOrders
2934
+ * @description fetches information on multiple canceled orders made by the user
2935
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_gethistoricalorders
2936
+ * @param {string} symbol unified market symbol of the orders
2937
+ * @param {int} [since] timestamp in ms of the earliest order, default is undefined
2938
+ * @param {int} [limit] the maximum number of canceled order structures to retrieve
2939
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2940
+ * @returns {object} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2941
+ */
2942
+ return await this.fetchOrdersByStatus('CANCELLED', symbol, since, limit, params);
2943
+ }
2944
+ async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
2945
+ /**
2946
+ * @method
2947
+ * @name coinbase#fetchOHLCV
2948
+ * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
2949
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getcandles
2950
+ * @param {string} symbol unified symbol of the market to fetch OHLCV data for
2951
+ * @param {string} timeframe the length of time each candle represents
2952
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
2953
+ * @param {int} [limit] the maximum amount of candles to fetch, not used by coinbase
2954
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2955
+ * @param {int} [params.until] the latest time in ms to fetch trades for
2956
+ * @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)
2957
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
2958
+ */
2959
+ await this.loadMarkets();
2960
+ let paginate = false;
2961
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchOHLCV', 'paginate', false);
2962
+ if (paginate) {
2963
+ return await this.fetchPaginatedCallDeterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 299);
2964
+ }
2965
+ const market = this.market(symbol);
2966
+ const request = {
2967
+ 'product_id': market['id'],
2968
+ 'granularity': this.safeString(this.timeframes, timeframe, timeframe),
2969
+ };
2970
+ const until = this.safeValueN(params, ['until', 'till', 'end']);
2971
+ params = this.omit(params, ['until', 'till']);
2972
+ const duration = this.parseTimeframe(timeframe);
2973
+ const candles300 = 300 * duration;
2974
+ let sinceString = undefined;
2975
+ if (since !== undefined) {
2976
+ sinceString = this.numberToString(this.parseToInt(since / 1000));
2977
+ }
2978
+ else {
2979
+ const now = this.seconds().toString();
2980
+ sinceString = Precise["default"].stringSub(now, candles300.toString());
2981
+ }
2982
+ request['start'] = sinceString;
2983
+ let endString = this.numberToString(until);
2984
+ if (until === undefined) {
2985
+ // 300 candles max
2986
+ endString = Precise["default"].stringAdd(sinceString, candles300.toString());
2987
+ }
2988
+ request['end'] = endString;
2989
+ const response = await this.v3PrivateGetBrokerageProductsProductIdCandles(this.extend(request, params));
2990
+ //
2991
+ // {
2992
+ // "candles": [
2993
+ // {
2994
+ // "start": "1673391780",
2995
+ // "low": "17414.36",
2996
+ // "high": "17417.99",
2997
+ // "open": "17417.74",
2998
+ // "close": "17417.38",
2999
+ // "volume": "1.87780853"
3000
+ // },
3001
+ // ]
3002
+ // }
3003
+ //
3004
+ const candles = this.safeValue(response, 'candles', []);
3005
+ return this.parseOHLCVs(candles, market, timeframe, since, limit);
3006
+ }
3007
+ parseOHLCV(ohlcv, market = undefined) {
3008
+ //
3009
+ // [
3010
+ // {
3011
+ // "start": "1673391780",
3012
+ // "low": "17414.36",
3013
+ // "high": "17417.99",
3014
+ // "open": "17417.74",
3015
+ // "close": "17417.38",
3016
+ // "volume": "1.87780853"
3017
+ // },
3018
+ // ]
3019
+ //
3020
+ return [
3021
+ this.safeTimestamp(ohlcv, 'start'),
3022
+ this.safeNumber(ohlcv, 'open'),
3023
+ this.safeNumber(ohlcv, 'high'),
3024
+ this.safeNumber(ohlcv, 'low'),
3025
+ this.safeNumber(ohlcv, 'close'),
3026
+ this.safeNumber(ohlcv, 'volume'),
3027
+ ];
3028
+ }
3029
+ async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
3030
+ /**
3031
+ * @method
3032
+ * @name coinbase#fetchTrades
3033
+ * @description get the list of most recent trades for a particular symbol
3034
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getmarkettrades
3035
+ * @param {string} symbol unified market symbol of the trades
3036
+ * @param {int} [since] not used by coinbase fetchTrades
3037
+ * @param {int} [limit] the maximum number of trade structures to fetch
3038
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3039
+ * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
3040
+ */
3041
+ await this.loadMarkets();
3042
+ const market = this.market(symbol);
3043
+ const request = {
3044
+ 'product_id': market['id'],
3045
+ };
3046
+ if (limit !== undefined) {
3047
+ request['limit'] = limit;
3048
+ }
3049
+ const response = await this.v3PrivateGetBrokerageProductsProductIdTicker(this.extend(request, params));
3050
+ //
3051
+ // {
3052
+ // "trades": [
3053
+ // {
3054
+ // "trade_id": "10092327",
3055
+ // "product_id": "BTC-USDT",
3056
+ // "price": "17488.12",
3057
+ // "size": "0.0000623",
3058
+ // "time": "2023-01-11T00:52:37.557001Z",
3059
+ // "side": "BUY",
3060
+ // "bid": "",
3061
+ // "ask": ""
3062
+ // },
3063
+ // ]
3064
+ // }
3065
+ //
3066
+ const trades = this.safeValue(response, 'trades', []);
3067
+ return this.parseTrades(trades, market, since, limit);
3068
+ }
3069
+ async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
3070
+ /**
3071
+ * @method
3072
+ * @name coinbase#fetchMyTrades
3073
+ * @description fetch all trades made by the user
3074
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getfills
3075
+ * @param {string} symbol unified market symbol of the trades
3076
+ * @param {int} [since] timestamp in ms of the earliest order, default is undefined
3077
+ * @param {int} [limit] the maximum number of trade structures to fetch
3078
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3079
+ * @param {int} [params.until] the latest time in ms to fetch trades for
3080
+ * @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)
3081
+ * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
3082
+ */
3083
+ await this.loadMarkets();
3084
+ let paginate = false;
3085
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchMyTrades', 'paginate');
3086
+ if (paginate) {
3087
+ return await this.fetchPaginatedCallCursor('fetchMyTrades', symbol, since, limit, params, 'cursor', 'cursor', undefined, 100);
3088
+ }
3089
+ let market = undefined;
3090
+ if (symbol !== undefined) {
3091
+ market = this.market(symbol);
3092
+ }
3093
+ const request = {};
3094
+ if (market !== undefined) {
3095
+ request['product_id'] = market['id'];
3096
+ }
3097
+ if (limit !== undefined) {
3098
+ request['limit'] = limit;
3099
+ }
3100
+ if (since !== undefined) {
3101
+ request['start_sequence_timestamp'] = this.iso8601(since);
3102
+ }
3103
+ const until = this.safeValueN(params, ['until', 'till']);
3104
+ if (until !== undefined) {
3105
+ params = this.omit(params, ['until', 'till']);
3106
+ request['end_sequence_timestamp'] = this.iso8601(until);
3107
+ }
3108
+ const response = await this.v3PrivateGetBrokerageOrdersHistoricalFills(this.extend(request, params));
3109
+ //
3110
+ // {
3111
+ // "fills": [
3112
+ // {
3113
+ // "entry_id": "b88b82cc89e326a2778874795102cbafd08dd979a2a7a3c69603fc4c23c2e010",
3114
+ // "trade_id": "cdc39e45-bbd3-44ec-bf02-61742dfb16a1",
3115
+ // "order_id": "813a53c5-3e39-47bb-863d-2faf685d22d8",
3116
+ // "trade_time": "2023-01-18T01:37:38.091377090Z",
3117
+ // "trade_type": "FILL",
3118
+ // "price": "21220.64",
3119
+ // "size": "0.0046830664333996",
3120
+ // "commission": "0.0000280983986004",
3121
+ // "product_id": "BTC-USDT",
3122
+ // "sequence_timestamp": "2023-01-18T01:37:38.092520Z",
3123
+ // "liquidity_indicator": "UNKNOWN_LIQUIDITY_INDICATOR",
3124
+ // "size_in_quote": true,
3125
+ // "user_id": "1111111-1111-1111-1111-111111111111",
3126
+ // "side": "BUY"
3127
+ // },
3128
+ // ],
3129
+ // "cursor": ""
3130
+ // }
3131
+ //
3132
+ const trades = this.safeValue(response, 'fills', []);
3133
+ const first = this.safeValue(trades, 0);
3134
+ const cursor = this.safeString(response, 'cursor');
3135
+ if ((cursor !== undefined) && (cursor !== '')) {
3136
+ first['cursor'] = cursor;
3137
+ trades[0] = first;
3138
+ }
3139
+ return this.parseTrades(trades, market, since, limit);
3140
+ }
3141
+ async fetchOrderBook(symbol, limit = undefined, params = {}) {
3142
+ /**
3143
+ * @method
3144
+ * @name coinbase#fetchOrderBook
3145
+ * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
3146
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getproductbook
3147
+ * @param {string} symbol unified symbol of the market to fetch the order book for
3148
+ * @param {int} [limit] the maximum amount of order book entries to return
3149
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3150
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
3151
+ */
3152
+ await this.loadMarkets();
3153
+ const market = this.market(symbol);
3154
+ const request = {
3155
+ 'product_id': market['id'],
3156
+ };
3157
+ if (limit !== undefined) {
3158
+ request['limit'] = limit;
3159
+ }
3160
+ const response = await this.v3PrivateGetBrokerageProductBook(this.extend(request, params));
3161
+ //
3162
+ // {
3163
+ // "pricebook": {
3164
+ // "product_id": "BTC-USDT",
3165
+ // "bids": [
3166
+ // {
3167
+ // "price": "30757.85",
3168
+ // "size": "0.115"
3169
+ // },
3170
+ // ],
3171
+ // "asks": [
3172
+ // {
3173
+ // "price": "30759.07",
3174
+ // "size": "0.04877659"
3175
+ // },
3176
+ // ],
3177
+ // "time": "2023-06-30T04:02:40.533606Z"
3178
+ // }
3179
+ // }
3180
+ //
3181
+ const data = this.safeValue(response, 'pricebook', {});
3182
+ const time = this.safeString(data, 'time');
3183
+ const timestamp = this.parse8601(time);
3184
+ return this.parseOrderBook(data, symbol, timestamp, 'bids', 'asks', 'price', 'size');
3185
+ }
3186
+ async fetchBidsAsks(symbols = undefined, params = {}) {
3187
+ /**
3188
+ * @method
3189
+ * @name coinbase#fetchBidsAsks
3190
+ * @description fetches the bid and ask price and volume for multiple markets
3191
+ * @see https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getbestbidask
3192
+ * @param {string[]} [symbols] unified symbols of the markets to fetch the bids and asks for, all markets are returned if not assigned
3193
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3194
+ * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
3195
+ */
3196
+ await this.loadMarkets();
3197
+ symbols = this.marketSymbols(symbols);
3198
+ // the 'product_ids' param isn't working properly and returns {"pricebooks":[]} when defined
3199
+ const response = await this.v3PrivateGetBrokerageBestBidAsk(params);
3200
+ //
3201
+ // {
3202
+ // "pricebooks": [
3203
+ // {
3204
+ // "product_id": "TRAC-EUR",
3205
+ // "bids": [
3206
+ // {
3207
+ // "price": "0.2384",
3208
+ // "size": "386.1"
3209
+ // }
3210
+ // ],
3211
+ // "asks": [
3212
+ // {
3213
+ // "price": "0.2406",
3214
+ // "size": "672"
3215
+ // }
3216
+ // ],
3217
+ // "time": "2023-06-30T07:15:24.656044Z"
3218
+ // },
3219
+ // ]
3220
+ // }
3221
+ //
3222
+ const tickers = this.safeValue(response, 'pricebooks', []);
3223
+ return this.parseTickers(tickers, symbols);
3224
+ }
3225
+ async withdraw(code, amount, address, tag = undefined, params = {}) {
3226
+ /**
3227
+ * @method
3228
+ * @name coinbase#withdraw
3229
+ * @description make a withdrawal
3230
+ * @see https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-transactions#send-money
3231
+ * @param {string} code unified currency code
3232
+ * @param {float} amount the amount to withdraw
3233
+ * @param {string} address the address to withdraw to
3234
+ * @param {string} [tag] an optional tag for the withdrawal
3235
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3236
+ * @returns {object} a [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure}
3237
+ */
3238
+ [tag, params] = this.handleWithdrawTagAndParams(tag, params);
3239
+ this.checkAddress(address);
3240
+ await this.loadMarkets();
3241
+ const currency = this.currency(code);
3242
+ let accountId = this.safeString2(params, 'account_id', 'accountId');
3243
+ params = this.omit(params, ['account_id', 'accountId']);
3244
+ if (accountId === undefined) {
3245
+ if (code === undefined) {
3246
+ throw new errors.ArgumentsRequired(this.id + ' withdraw() requires an account_id (or accountId) parameter OR a currency code argument');
3247
+ }
3248
+ accountId = await this.findAccountId(code);
3249
+ if (accountId === undefined) {
3250
+ throw new errors.ExchangeError(this.id + ' withdraw() could not find account id for ' + code);
3251
+ }
3252
+ }
3253
+ const request = {
3254
+ 'account_id': accountId,
3255
+ 'type': 'send',
3256
+ 'to': address,
3257
+ 'amount': amount,
3258
+ 'currency': currency['id'],
3259
+ };
3260
+ if (tag !== undefined) {
3261
+ request['destination_tag'] = tag;
3262
+ }
3263
+ const response = await this.v2PrivatePostAccountsAccountIdTransactions(this.extend(request, params));
3264
+ //
3265
+ // {
3266
+ // "data": {
3267
+ // "id": "a1794ecf-5693-55fa-70cf-ef731748ed82",
3268
+ // "type": "send",
3269
+ // "status": "pending",
3270
+ // "amount": {
3271
+ // "amount": "-14.008308",
3272
+ // "currency": "USDC"
3273
+ // },
3274
+ // "native_amount": {
3275
+ // "amount": "-18.74",
3276
+ // "currency": "CAD"
3277
+ // },
3278
+ // "description": null,
3279
+ // "created_at": "2024-01-12T01:27:31Z",
3280
+ // "updated_at": "2024-01-12T01:27:31Z",
3281
+ // "resource": "transaction",
3282
+ // "resource_path": "/v2/accounts/a34bgfad-ed67-538b-bffc-730c98c10da0/transactions/a1794ecf-5693-55fa-70cf-ef731748ed82",
3283
+ // "instant_exchange": false,
3284
+ // "network": {
3285
+ // "status": "pending",
3286
+ // "status_description": "Pending (est. less than 10 minutes)",
3287
+ // "transaction_fee": {
3288
+ // "amount": "4.008308",
3289
+ // "currency": "USDC"
3290
+ // },
3291
+ // "transaction_amount": {
3292
+ // "amount": "10.000000",
3293
+ // "currency": "USDC"
3294
+ // },
3295
+ // "confirmations": 0
3296
+ // },
3297
+ // "to": {
3298
+ // "resource": "ethereum_address",
3299
+ // "address": "0x9...",
3300
+ // "currency": "USDC",
3301
+ // "address_info": {
3302
+ // "address": "0x9..."
3303
+ // }
3304
+ // },
3305
+ // "idem": "748d8591-dg9a-7831-a45b-crd61dg78762",
3306
+ // "details": {
3307
+ // "title": "Sent USDC",
3308
+ // "subtitle": "To USDC address on Ethereum network",
3309
+ // "header": "Sent 14.008308 USDC ($18.74)",
3310
+ // "health": "warning"
3311
+ // },
3312
+ // "hide_native_amount": false
3313
+ // }
3314
+ // }
3315
+ //
3316
+ const data = this.safeValue(response, 'data', {});
3317
+ return this.parseTransaction(data, currency);
3318
+ }
3319
+ sign(path, api = [], method = 'GET', params = {}, headers = undefined, body = undefined) {
3320
+ const version = api[0];
3321
+ const signed = api[1] === 'private';
3322
+ const pathPart = (version === 'v3') ? 'api/v3' : 'v2';
3323
+ let fullPath = '/' + pathPart + '/' + this.implodeParams(path, params);
3324
+ const query = this.omit(params, this.extractParams(path));
3325
+ const savedPath = fullPath;
3326
+ if (method === 'GET') {
3327
+ if (Object.keys(query).length) {
3328
+ fullPath += '?' + this.urlencode(query);
3329
+ }
3330
+ }
3331
+ const url = this.urls['api']['rest'] + fullPath;
3332
+ if (signed) {
3333
+ const authorization = this.safeString(this.headers, 'Authorization');
3334
+ if (authorization !== undefined) {
3335
+ headers = {
3336
+ 'Authorization': authorization,
3337
+ 'Content-Type': 'application/json',
3338
+ };
3339
+ }
3340
+ else if (this.token) {
3341
+ headers = {
3342
+ 'Authorization': 'Bearer ' + this.token,
3343
+ 'Content-Type': 'application/json',
3344
+ };
3345
+ }
3346
+ else {
3347
+ this.checkRequiredCredentials();
3348
+ const nonce = this.nonce().toString();
3349
+ let payload = '';
3350
+ if (method !== 'GET') {
3351
+ if (Object.keys(query).length) {
3352
+ body = this.json(query);
3353
+ payload = body;
3354
+ }
3355
+ }
3356
+ let auth = undefined;
3357
+ if (version === 'v3') {
3358
+ auth = nonce + method + savedPath + payload;
3359
+ }
3360
+ else {
3361
+ auth = nonce + method + fullPath + payload;
3362
+ }
3363
+ const signature = this.hmac(this.encode(auth), this.encode(this.secret), sha256.sha256);
3364
+ headers = {
3365
+ 'CB-ACCESS-KEY': this.apiKey,
3366
+ 'CB-ACCESS-SIGN': signature,
3367
+ 'CB-ACCESS-TIMESTAMP': nonce,
3368
+ 'Content-Type': 'application/json',
3369
+ };
3370
+ }
3371
+ }
3372
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
3373
+ }
3374
+ handleErrors(code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
3375
+ if (response === undefined) {
3376
+ return undefined; // fallback to default error handler
3377
+ }
3378
+ const feedback = this.id + ' ' + body;
3379
+ //
3380
+ // {"error": "invalid_request", "error_description": "The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed."}
3381
+ //
3382
+ // or
3383
+ //
3384
+ // {
3385
+ // "errors": [
3386
+ // {
3387
+ // "id": "not_found",
3388
+ // "message": "Not found"
3389
+ // }
3390
+ // ]
3391
+ // }
3392
+ //
3393
+ let errorCode = this.safeString(response, 'error');
3394
+ if (errorCode !== undefined) {
3395
+ const errorMessage = this.safeString(response, 'error_description');
3396
+ this.throwExactlyMatchedException(this.exceptions['exact'], errorCode, feedback);
3397
+ this.throwBroadlyMatchedException(this.exceptions['broad'], errorMessage, feedback);
3398
+ throw new errors.ExchangeError(feedback);
3399
+ }
3400
+ const errors$1 = this.safeValue(response, 'errors');
3401
+ if (errors$1 !== undefined) {
3402
+ if (Array.isArray(errors$1)) {
3403
+ const numErrors = errors$1.length;
3404
+ if (numErrors > 0) {
3405
+ errorCode = this.safeString(errors$1[0], 'id');
3406
+ const errorMessage = this.safeString(errors$1[0], 'message');
3407
+ if (errorCode !== undefined) {
3408
+ this.throwExactlyMatchedException(this.exceptions['exact'], errorCode, feedback);
3409
+ this.throwBroadlyMatchedException(this.exceptions['broad'], errorMessage, feedback);
3410
+ throw new errors.ExchangeError(feedback);
3411
+ }
3412
+ }
3413
+ }
3414
+ }
3415
+ const advancedTrade = this.options['advanced'];
3416
+ const data = this.safeValue(response, 'data');
3417
+ if ((data === undefined) && (!advancedTrade)) {
3418
+ throw new errors.ExchangeError(this.id + ' failed due to a malformed response ' + this.json(response));
3419
+ }
3420
+ return undefined;
3421
+ }
3422
+ }
3423
+
3424
+ module.exports = coinbase;