ccxt 4.2.77__py2.py3-none-any.whl → 4.4.49__py2.py3-none-any.whl

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 (546) hide show
  1. ccxt/__init__.py +36 -14
  2. ccxt/abstract/alpaca.py +4 -0
  3. ccxt/abstract/bigone.py +1 -1
  4. ccxt/abstract/binance.py +112 -48
  5. ccxt/abstract/binancecoinm.py +112 -48
  6. ccxt/abstract/binanceus.py +147 -83
  7. ccxt/abstract/binanceusdm.py +112 -48
  8. ccxt/abstract/bingx.py +133 -78
  9. ccxt/abstract/bitbank.py +5 -0
  10. ccxt/abstract/bitfinex.py +136 -65
  11. ccxt/abstract/bitfinex1.py +69 -0
  12. ccxt/abstract/bitflyer.py +1 -0
  13. ccxt/abstract/bitget.py +8 -1
  14. ccxt/abstract/bitmart.py +13 -1
  15. ccxt/abstract/bitopro.py +1 -0
  16. ccxt/abstract/bitpanda.py +0 -12
  17. ccxt/abstract/bitrue.py +3 -3
  18. ccxt/abstract/bitstamp.py +26 -3
  19. ccxt/abstract/blofin.py +24 -0
  20. ccxt/abstract/btcbox.py +1 -0
  21. ccxt/abstract/bybit.py +29 -14
  22. ccxt/abstract/cex.py +28 -29
  23. ccxt/abstract/coinbase.py +6 -0
  24. ccxt/abstract/coinbaseadvanced.py +94 -0
  25. ccxt/abstract/{coinbasepro.py → coinbaseexchange.py} +1 -0
  26. ccxt/abstract/coinbaseinternational.py +1 -1
  27. ccxt/abstract/coincatch.py +94 -0
  28. ccxt/abstract/coinex.py +233 -123
  29. ccxt/abstract/coinmetro.py +1 -0
  30. ccxt/abstract/cryptocom.py +14 -0
  31. ccxt/abstract/defx.py +69 -0
  32. ccxt/abstract/deribit.py +1 -0
  33. ccxt/abstract/digifinex.py +1 -0
  34. ccxt/abstract/ellipx.py +25 -0
  35. ccxt/abstract/gate.py +20 -0
  36. ccxt/abstract/gateio.py +20 -0
  37. ccxt/abstract/gemini.py +1 -0
  38. ccxt/abstract/hashkey.py +67 -0
  39. ccxt/abstract/hyperliquid.py +1 -1
  40. ccxt/abstract/independentreserve.py +6 -0
  41. ccxt/abstract/kraken.py +4 -3
  42. ccxt/abstract/krakenfutures.py +4 -0
  43. ccxt/abstract/kucoin.py +24 -0
  44. ccxt/abstract/kucoinfutures.py +34 -0
  45. ccxt/abstract/luno.py +2 -0
  46. ccxt/abstract/mexc.py +4 -0
  47. ccxt/abstract/myokx.py +340 -0
  48. ccxt/abstract/oceanex.py +5 -0
  49. ccxt/abstract/okx.py +30 -0
  50. ccxt/abstract/onetrading.py +0 -12
  51. ccxt/abstract/oxfun.py +34 -0
  52. ccxt/abstract/paradex.py +40 -0
  53. ccxt/abstract/phemex.py +1 -0
  54. ccxt/abstract/upbit.py +4 -0
  55. ccxt/abstract/vertex.py +19 -0
  56. ccxt/abstract/whitebit.py +31 -1
  57. ccxt/abstract/woo.py +6 -2
  58. ccxt/abstract/woofipro.py +119 -0
  59. ccxt/abstract/xt.py +153 -0
  60. ccxt/abstract/zonda.py +6 -0
  61. ccxt/ace.py +164 -60
  62. ccxt/alpaca.py +727 -63
  63. ccxt/ascendex.py +395 -249
  64. ccxt/async_support/__init__.py +36 -14
  65. ccxt/async_support/ace.py +164 -60
  66. ccxt/async_support/alpaca.py +727 -63
  67. ccxt/async_support/ascendex.py +396 -249
  68. ccxt/async_support/base/exchange.py +531 -155
  69. ccxt/async_support/base/ws/aiohttp_client.py +28 -5
  70. ccxt/async_support/base/ws/cache.py +3 -2
  71. ccxt/async_support/base/ws/client.py +26 -5
  72. ccxt/async_support/base/ws/fast_client.py +4 -3
  73. ccxt/async_support/base/ws/functions.py +1 -1
  74. ccxt/async_support/base/ws/future.py +40 -31
  75. ccxt/async_support/base/ws/order_book_side.py +3 -0
  76. ccxt/async_support/bequant.py +1 -1
  77. ccxt/async_support/bigone.py +329 -202
  78. ccxt/async_support/binance.py +3030 -1087
  79. ccxt/async_support/binancecoinm.py +2 -1
  80. ccxt/async_support/binanceus.py +12 -1
  81. ccxt/async_support/binanceusdm.py +3 -1
  82. ccxt/async_support/bingx.py +3205 -937
  83. ccxt/async_support/bit2c.py +119 -38
  84. ccxt/async_support/bitbank.py +215 -76
  85. ccxt/async_support/bitbns.py +124 -53
  86. ccxt/async_support/bitfinex.py +3236 -1078
  87. ccxt/async_support/bitfinex1.py +1711 -0
  88. ccxt/async_support/bitflyer.py +238 -49
  89. ccxt/async_support/bitget.py +1525 -573
  90. ccxt/async_support/bithumb.py +199 -65
  91. ccxt/async_support/bitmart.py +1320 -435
  92. ccxt/async_support/bitmex.py +308 -111
  93. ccxt/async_support/bitopro.py +256 -96
  94. ccxt/async_support/bitrue.py +365 -233
  95. ccxt/async_support/bitso.py +201 -89
  96. ccxt/async_support/bitstamp.py +438 -269
  97. ccxt/async_support/bitteam.py +179 -73
  98. ccxt/async_support/bitvavo.py +180 -70
  99. ccxt/async_support/bl3p.py +92 -25
  100. ccxt/async_support/blockchaincom.py +193 -79
  101. ccxt/async_support/blofin.py +392 -148
  102. ccxt/async_support/btcalpha.py +161 -55
  103. ccxt/async_support/btcbox.py +250 -34
  104. ccxt/async_support/btcmarkets.py +232 -85
  105. ccxt/async_support/btcturk.py +159 -60
  106. ccxt/async_support/bybit.py +2231 -1193
  107. ccxt/async_support/cex.py +1409 -1329
  108. ccxt/async_support/coinbase.py +1454 -287
  109. ccxt/async_support/coinbaseadvanced.py +17 -0
  110. ccxt/async_support/{coinbasepro.py → coinbaseexchange.py} +233 -99
  111. ccxt/async_support/coinbaseinternational.py +428 -88
  112. ccxt/async_support/coincatch.py +5152 -0
  113. ccxt/async_support/coincheck.py +121 -38
  114. ccxt/async_support/coinex.py +4020 -3339
  115. ccxt/async_support/coinlist.py +273 -116
  116. ccxt/async_support/coinmate.py +204 -97
  117. ccxt/async_support/coinmetro.py +203 -110
  118. ccxt/async_support/coinone.py +142 -68
  119. ccxt/async_support/coinsph.py +223 -97
  120. ccxt/async_support/coinspot.py +137 -62
  121. ccxt/async_support/cryptocom.py +515 -185
  122. ccxt/async_support/currencycom.py +203 -85
  123. ccxt/async_support/defx.py +2066 -0
  124. ccxt/async_support/delta.py +404 -109
  125. ccxt/async_support/deribit.py +639 -323
  126. ccxt/async_support/digifinex.py +465 -233
  127. ccxt/async_support/ellipx.py +1887 -0
  128. ccxt/async_support/exmo.py +317 -128
  129. ccxt/async_support/gate.py +1472 -463
  130. ccxt/async_support/gemini.py +206 -84
  131. ccxt/async_support/hashkey.py +4164 -0
  132. ccxt/async_support/hitbtc.py +433 -178
  133. ccxt/async_support/hollaex.py +207 -83
  134. ccxt/async_support/htx.py +1095 -563
  135. ccxt/async_support/huobijp.py +178 -56
  136. ccxt/async_support/hyperliquid.py +1678 -292
  137. ccxt/async_support/idex.py +219 -95
  138. ccxt/async_support/independentreserve.py +300 -31
  139. ccxt/async_support/indodax.py +226 -62
  140. ccxt/async_support/kraken.py +871 -354
  141. ccxt/async_support/krakenfutures.py +324 -100
  142. ccxt/async_support/kucoin.py +917 -357
  143. ccxt/async_support/kucoinfutures.py +1004 -149
  144. ccxt/async_support/kuna.py +198 -107
  145. ccxt/async_support/latoken.py +199 -79
  146. ccxt/async_support/lbank.py +360 -113
  147. ccxt/async_support/luno.py +185 -62
  148. ccxt/async_support/lykke.py +168 -55
  149. ccxt/async_support/mercado.py +101 -29
  150. ccxt/async_support/mexc.py +995 -429
  151. ccxt/async_support/myokx.py +53 -0
  152. ccxt/async_support/ndax.py +234 -82
  153. ccxt/async_support/novadax.py +195 -75
  154. ccxt/async_support/oceanex.py +244 -59
  155. ccxt/async_support/okcoin.py +301 -165
  156. ccxt/async_support/okx.py +1776 -454
  157. ccxt/async_support/onetrading.py +198 -414
  158. ccxt/async_support/oxfun.py +2898 -0
  159. ccxt/async_support/p2b.py +142 -52
  160. ccxt/async_support/paradex.py +2085 -0
  161. ccxt/async_support/paymium.py +56 -32
  162. ccxt/async_support/phemex.py +572 -196
  163. ccxt/async_support/poloniex.py +218 -95
  164. ccxt/async_support/poloniexfutures.py +260 -92
  165. ccxt/async_support/probit.py +143 -110
  166. ccxt/async_support/timex.py +123 -70
  167. ccxt/async_support/tokocrypto.py +129 -93
  168. ccxt/async_support/tradeogre.py +39 -25
  169. ccxt/async_support/upbit.py +322 -113
  170. ccxt/async_support/vertex.py +2983 -0
  171. ccxt/async_support/wavesexchange.py +227 -173
  172. ccxt/async_support/wazirx.py +145 -65
  173. ccxt/async_support/whitebit.py +533 -138
  174. ccxt/async_support/woo.py +1137 -296
  175. ccxt/async_support/woofipro.py +2716 -0
  176. ccxt/async_support/xt.py +4628 -0
  177. ccxt/async_support/yobit.py +160 -92
  178. ccxt/async_support/zaif.py +80 -33
  179. ccxt/async_support/zonda.py +140 -69
  180. ccxt/base/errors.py +51 -20
  181. ccxt/base/exchange.py +1722 -480
  182. ccxt/base/precise.py +10 -0
  183. ccxt/base/types.py +223 -4
  184. ccxt/bequant.py +1 -1
  185. ccxt/bigone.py +329 -202
  186. ccxt/binance.py +3030 -1087
  187. ccxt/binancecoinm.py +2 -1
  188. ccxt/binanceus.py +12 -1
  189. ccxt/binanceusdm.py +3 -1
  190. ccxt/bingx.py +3205 -937
  191. ccxt/bit2c.py +119 -38
  192. ccxt/bitbank.py +215 -76
  193. ccxt/bitbns.py +124 -53
  194. ccxt/bitfinex.py +3235 -1078
  195. ccxt/bitfinex1.py +1710 -0
  196. ccxt/bitflyer.py +238 -49
  197. ccxt/bitget.py +1525 -573
  198. ccxt/bithumb.py +198 -65
  199. ccxt/bitmart.py +1320 -435
  200. ccxt/bitmex.py +308 -111
  201. ccxt/bitopro.py +256 -96
  202. ccxt/bitrue.py +365 -233
  203. ccxt/bitso.py +201 -89
  204. ccxt/bitstamp.py +438 -269
  205. ccxt/bitteam.py +179 -73
  206. ccxt/bitvavo.py +180 -70
  207. ccxt/bl3p.py +92 -25
  208. ccxt/blockchaincom.py +193 -79
  209. ccxt/blofin.py +392 -148
  210. ccxt/btcalpha.py +161 -55
  211. ccxt/btcbox.py +250 -34
  212. ccxt/btcmarkets.py +232 -85
  213. ccxt/btcturk.py +159 -60
  214. ccxt/bybit.py +2231 -1193
  215. ccxt/cex.py +1408 -1329
  216. ccxt/coinbase.py +1454 -287
  217. ccxt/coinbaseadvanced.py +17 -0
  218. ccxt/{coinbasepro.py → coinbaseexchange.py} +233 -99
  219. ccxt/coinbaseinternational.py +428 -88
  220. ccxt/coincatch.py +5152 -0
  221. ccxt/coincheck.py +121 -38
  222. ccxt/coinex.py +4020 -3339
  223. ccxt/coinlist.py +273 -116
  224. ccxt/coinmate.py +204 -97
  225. ccxt/coinmetro.py +203 -110
  226. ccxt/coinone.py +142 -68
  227. ccxt/coinsph.py +223 -97
  228. ccxt/coinspot.py +137 -62
  229. ccxt/cryptocom.py +515 -185
  230. ccxt/currencycom.py +203 -85
  231. ccxt/defx.py +2065 -0
  232. ccxt/delta.py +404 -109
  233. ccxt/deribit.py +639 -323
  234. ccxt/digifinex.py +465 -233
  235. ccxt/ellipx.py +1887 -0
  236. ccxt/exmo.py +317 -128
  237. ccxt/gate.py +1472 -463
  238. ccxt/gemini.py +206 -84
  239. ccxt/hashkey.py +4164 -0
  240. ccxt/hitbtc.py +433 -178
  241. ccxt/hollaex.py +207 -83
  242. ccxt/htx.py +1095 -563
  243. ccxt/huobijp.py +178 -56
  244. ccxt/hyperliquid.py +1677 -292
  245. ccxt/idex.py +219 -95
  246. ccxt/independentreserve.py +299 -31
  247. ccxt/indodax.py +226 -62
  248. ccxt/kraken.py +871 -354
  249. ccxt/krakenfutures.py +324 -100
  250. ccxt/kucoin.py +917 -357
  251. ccxt/kucoinfutures.py +1004 -149
  252. ccxt/kuna.py +198 -107
  253. ccxt/latoken.py +199 -79
  254. ccxt/lbank.py +360 -113
  255. ccxt/luno.py +185 -62
  256. ccxt/lykke.py +168 -55
  257. ccxt/mercado.py +101 -29
  258. ccxt/mexc.py +994 -429
  259. ccxt/myokx.py +53 -0
  260. ccxt/ndax.py +234 -82
  261. ccxt/novadax.py +195 -75
  262. ccxt/oceanex.py +244 -59
  263. ccxt/okcoin.py +301 -165
  264. ccxt/okx.py +1776 -454
  265. ccxt/onetrading.py +198 -414
  266. ccxt/oxfun.py +2897 -0
  267. ccxt/p2b.py +142 -52
  268. ccxt/paradex.py +2085 -0
  269. ccxt/paymium.py +56 -32
  270. ccxt/phemex.py +572 -196
  271. ccxt/poloniex.py +218 -95
  272. ccxt/poloniexfutures.py +260 -92
  273. ccxt/pro/__init__.py +29 -5
  274. ccxt/pro/alpaca.py +32 -17
  275. ccxt/pro/ascendex.py +62 -14
  276. ccxt/pro/bequant.py +4 -0
  277. ccxt/pro/binance.py +1596 -329
  278. ccxt/pro/binancecoinm.py +1 -0
  279. ccxt/pro/binanceus.py +2 -9
  280. ccxt/pro/binanceusdm.py +2 -0
  281. ccxt/pro/bingx.py +527 -134
  282. ccxt/pro/bitcoincom.py +4 -1
  283. ccxt/pro/bitfinex.py +731 -266
  284. ccxt/pro/bitfinex1.py +635 -0
  285. ccxt/pro/bitget.py +726 -357
  286. ccxt/pro/bithumb.py +380 -0
  287. ccxt/pro/bitmart.py +143 -39
  288. ccxt/pro/bitmex.py +199 -40
  289. ccxt/pro/bitopro.py +25 -13
  290. ccxt/pro/bitrue.py +31 -32
  291. ccxt/pro/bitstamp.py +7 -6
  292. ccxt/pro/bitvavo.py +203 -81
  293. ccxt/pro/blockchaincom.py +30 -17
  294. ccxt/pro/blofin.py +692 -0
  295. ccxt/pro/bybit.py +791 -82
  296. ccxt/pro/cex.py +99 -51
  297. ccxt/pro/coinbase.py +220 -30
  298. ccxt/{async_support/hitbtc3.py → pro/coinbaseadvanced.py} +5 -5
  299. ccxt/pro/{coinbasepro.py → coinbaseexchange.py} +19 -19
  300. ccxt/pro/coinbaseinternational.py +193 -30
  301. ccxt/pro/coincatch.py +1464 -0
  302. ccxt/pro/coincheck.py +11 -6
  303. ccxt/pro/coinex.py +965 -665
  304. ccxt/pro/coinone.py +17 -10
  305. ccxt/pro/cryptocom.py +446 -66
  306. ccxt/pro/currencycom.py +11 -10
  307. ccxt/pro/defx.py +832 -0
  308. ccxt/pro/deribit.py +167 -31
  309. ccxt/pro/exmo.py +252 -20
  310. ccxt/pro/gate.py +729 -64
  311. ccxt/pro/gemini.py +44 -26
  312. ccxt/pro/hashkey.py +802 -0
  313. ccxt/pro/hitbtc.py +208 -103
  314. ccxt/pro/hollaex.py +25 -9
  315. ccxt/pro/htx.py +83 -39
  316. ccxt/pro/huobijp.py +17 -16
  317. ccxt/pro/hyperliquid.py +502 -31
  318. ccxt/pro/idex.py +28 -13
  319. ccxt/pro/independentreserve.py +21 -16
  320. ccxt/pro/kraken.py +298 -51
  321. ccxt/pro/krakenfutures.py +166 -75
  322. ccxt/pro/kucoin.py +395 -77
  323. ccxt/pro/kucoinfutures.py +400 -99
  324. ccxt/pro/lbank.py +52 -31
  325. ccxt/pro/luno.py +12 -10
  326. ccxt/pro/mexc.py +400 -50
  327. ccxt/pro/myokx.py +28 -0
  328. ccxt/pro/ndax.py +25 -12
  329. ccxt/pro/okcoin.py +28 -9
  330. ccxt/pro/okx.py +935 -124
  331. ccxt/pro/onetrading.py +41 -24
  332. ccxt/pro/oxfun.py +1054 -0
  333. ccxt/pro/p2b.py +100 -24
  334. ccxt/pro/paradex.py +352 -0
  335. ccxt/pro/phemex.py +92 -33
  336. ccxt/pro/poloniex.py +128 -49
  337. ccxt/pro/poloniexfutures.py +53 -32
  338. ccxt/pro/probit.py +92 -85
  339. ccxt/pro/upbit.py +401 -8
  340. ccxt/pro/vertex.py +943 -0
  341. ccxt/pro/wazirx.py +46 -28
  342. ccxt/pro/whitebit.py +65 -12
  343. ccxt/pro/woo.py +437 -65
  344. ccxt/pro/woofipro.py +1271 -0
  345. ccxt/pro/xt.py +1067 -0
  346. ccxt/probit.py +143 -110
  347. ccxt/static_dependencies/__init__.py +1 -1
  348. ccxt/static_dependencies/lark/__init__.py +38 -0
  349. ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
  350. ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
  351. ccxt/static_dependencies/lark/ast_utils.py +59 -0
  352. ccxt/static_dependencies/lark/common.py +86 -0
  353. ccxt/static_dependencies/lark/exceptions.py +292 -0
  354. ccxt/static_dependencies/lark/grammar.py +130 -0
  355. ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
  356. ccxt/static_dependencies/lark/indenter.py +143 -0
  357. ccxt/static_dependencies/lark/lark.py +658 -0
  358. ccxt/static_dependencies/lark/lexer.py +678 -0
  359. ccxt/static_dependencies/lark/load_grammar.py +1428 -0
  360. ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
  361. ccxt/static_dependencies/lark/parser_frontends.py +257 -0
  362. ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
  363. ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
  364. ccxt/static_dependencies/lark/parsers/earley.py +314 -0
  365. ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
  366. ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
  367. ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
  368. ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
  369. ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
  370. ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
  371. ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
  372. ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
  373. ccxt/static_dependencies/lark/py.typed +0 -0
  374. ccxt/static_dependencies/lark/reconstruct.py +107 -0
  375. ccxt/static_dependencies/lark/tools/__init__.py +70 -0
  376. ccxt/static_dependencies/lark/tools/nearley.py +202 -0
  377. ccxt/static_dependencies/lark/tools/serialize.py +32 -0
  378. ccxt/static_dependencies/lark/tools/standalone.py +196 -0
  379. ccxt/static_dependencies/lark/tree.py +267 -0
  380. ccxt/static_dependencies/lark/tree_matcher.py +186 -0
  381. ccxt/static_dependencies/lark/tree_templates.py +180 -0
  382. ccxt/static_dependencies/lark/utils.py +343 -0
  383. ccxt/static_dependencies/lark/visitors.py +596 -0
  384. ccxt/static_dependencies/marshmallow/__init__.py +81 -0
  385. ccxt/static_dependencies/marshmallow/base.py +65 -0
  386. ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
  387. ccxt/static_dependencies/marshmallow/decorators.py +231 -0
  388. ccxt/static_dependencies/marshmallow/error_store.py +60 -0
  389. ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
  390. ccxt/static_dependencies/marshmallow/fields.py +2114 -0
  391. ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
  392. ccxt/static_dependencies/marshmallow/py.typed +0 -0
  393. ccxt/static_dependencies/marshmallow/schema.py +1228 -0
  394. ccxt/static_dependencies/marshmallow/types.py +12 -0
  395. ccxt/static_dependencies/marshmallow/utils.py +378 -0
  396. ccxt/static_dependencies/marshmallow/validate.py +678 -0
  397. ccxt/static_dependencies/marshmallow/warnings.py +2 -0
  398. ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
  399. ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
  400. ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
  401. ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
  402. ccxt/static_dependencies/marshmallow_dataclass/py.typed +0 -0
  403. ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
  404. ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
  405. ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
  406. ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
  407. ccxt/static_dependencies/marshmallow_oneofschema/py.typed +0 -0
  408. ccxt/static_dependencies/starknet/__init__.py +0 -0
  409. ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
  410. ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
  411. ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
  412. ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
  413. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
  414. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
  415. ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
  416. ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
  417. ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
  418. ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
  419. ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
  420. ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
  421. ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
  422. ccxt/static_dependencies/starknet/common.py +15 -0
  423. ccxt/static_dependencies/starknet/constants.py +39 -0
  424. ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
  425. ccxt/static_dependencies/starknet/hash/address.py +79 -0
  426. ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
  427. ccxt/static_dependencies/starknet/hash/selector.py +16 -0
  428. ccxt/static_dependencies/starknet/hash/storage.py +12 -0
  429. ccxt/static_dependencies/starknet/hash/utils.py +78 -0
  430. ccxt/static_dependencies/starknet/models/__init__.py +0 -0
  431. ccxt/static_dependencies/starknet/models/typed_data.py +45 -0
  432. ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
  433. ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
  434. ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
  435. ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
  436. ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
  437. ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
  438. ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
  439. ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
  440. ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
  441. ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
  442. ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
  443. ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
  444. ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
  445. ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
  446. ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
  447. ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
  448. ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
  449. ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
  450. ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
  451. ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
  452. ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
  453. ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
  454. ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
  455. ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
  456. ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
  457. ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
  458. ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
  459. ccxt/static_dependencies/starknet/utils/schema.py +13 -0
  460. ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
  461. ccxt/static_dependencies/starkware/__init__.py +0 -0
  462. ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
  463. ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +50 -0
  464. ccxt/static_dependencies/starkware/crypto/math_utils.py +78 -0
  465. ccxt/static_dependencies/starkware/crypto/signature.py +2344 -0
  466. ccxt/static_dependencies/starkware/crypto/utils.py +63 -0
  467. ccxt/static_dependencies/sympy/__init__.py +0 -0
  468. ccxt/static_dependencies/sympy/core/__init__.py +0 -0
  469. ccxt/static_dependencies/sympy/core/intfunc.py +35 -0
  470. ccxt/static_dependencies/sympy/external/__init__.py +0 -0
  471. ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
  472. ccxt/static_dependencies/sympy/external/importtools.py +187 -0
  473. ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
  474. ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
  475. ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
  476. ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
  477. ccxt/test/{test_async.py → tests_async.py} +456 -391
  478. ccxt/test/tests_helpers.py +285 -0
  479. ccxt/test/tests_init.py +39 -0
  480. ccxt/test/{test_sync.py → tests_sync.py} +456 -393
  481. ccxt/timex.py +123 -70
  482. ccxt/tokocrypto.py +129 -93
  483. ccxt/tradeogre.py +39 -25
  484. ccxt/upbit.py +322 -113
  485. ccxt/vertex.py +2983 -0
  486. ccxt/wavesexchange.py +227 -173
  487. ccxt/wazirx.py +145 -65
  488. ccxt/whitebit.py +533 -138
  489. ccxt/woo.py +1137 -296
  490. ccxt/woofipro.py +2716 -0
  491. ccxt/xt.py +4627 -0
  492. ccxt/yobit.py +159 -92
  493. ccxt/zaif.py +80 -33
  494. ccxt/zonda.py +140 -69
  495. ccxt-4.4.49.dist-info/LICENSE.txt +21 -0
  496. ccxt-4.4.49.dist-info/METADATA +646 -0
  497. ccxt-4.4.49.dist-info/RECORD +669 -0
  498. {ccxt-4.2.77.dist-info → ccxt-4.4.49.dist-info}/WHEEL +1 -1
  499. ccxt/abstract/bitbay.py +0 -47
  500. ccxt/abstract/bitfinex2.py +0 -139
  501. ccxt/abstract/hitbtc3.py +0 -115
  502. ccxt/async_support/bitbay.py +0 -17
  503. ccxt/async_support/bitfinex2.py +0 -3496
  504. ccxt/async_support/flowbtc.py +0 -34
  505. ccxt/bitbay.py +0 -17
  506. ccxt/bitfinex2.py +0 -3496
  507. ccxt/flowbtc.py +0 -34
  508. ccxt/hitbtc3.py +0 -16
  509. ccxt/pro/bitfinex2.py +0 -1081
  510. ccxt/test/base/__init__.py +0 -28
  511. ccxt/test/base/test_account.py +0 -26
  512. ccxt/test/base/test_balance.py +0 -56
  513. ccxt/test/base/test_borrow_interest.py +0 -35
  514. ccxt/test/base/test_borrow_rate.py +0 -32
  515. ccxt/test/base/test_calculate_fee.py +0 -51
  516. ccxt/test/base/test_crypto.py +0 -127
  517. ccxt/test/base/test_currency.py +0 -76
  518. ccxt/test/base/test_datetime.py +0 -103
  519. ccxt/test/base/test_decimal_to_precision.py +0 -392
  520. ccxt/test/base/test_deep_extend.py +0 -68
  521. ccxt/test/base/test_deposit_withdrawal.py +0 -50
  522. ccxt/test/base/test_exchange_datetime_functions.py +0 -76
  523. ccxt/test/base/test_funding_rate_history.py +0 -29
  524. ccxt/test/base/test_last_price.py +0 -32
  525. ccxt/test/base/test_ledger_entry.py +0 -45
  526. ccxt/test/base/test_ledger_item.py +0 -48
  527. ccxt/test/base/test_leverage_tier.py +0 -33
  528. ccxt/test/base/test_margin_mode.py +0 -24
  529. ccxt/test/base/test_margin_modification.py +0 -35
  530. ccxt/test/base/test_market.py +0 -190
  531. ccxt/test/base/test_number.py +0 -411
  532. ccxt/test/base/test_ohlcv.py +0 -32
  533. ccxt/test/base/test_open_interest.py +0 -32
  534. ccxt/test/base/test_order.py +0 -64
  535. ccxt/test/base/test_order_book.py +0 -63
  536. ccxt/test/base/test_position.py +0 -60
  537. ccxt/test/base/test_shared_methods.py +0 -345
  538. ccxt/test/base/test_status.py +0 -24
  539. ccxt/test/base/test_throttle.py +0 -126
  540. ccxt/test/base/test_ticker.py +0 -86
  541. ccxt/test/base/test_trade.py +0 -47
  542. ccxt/test/base/test_trading_fee.py +0 -26
  543. ccxt/test/base/test_transaction.py +0 -39
  544. ccxt-4.2.77.dist-info/METADATA +0 -626
  545. ccxt-4.2.77.dist-info/RECORD +0 -534
  546. {ccxt-4.2.77.dist-info → ccxt-4.4.49.dist-info}/top_level.txt +0 -0
ccxt/coinbase.py CHANGED
@@ -6,9 +6,11 @@
6
6
  from ccxt.base.exchange import Exchange
7
7
  from ccxt.abstract.coinbase import ImplicitAPI
8
8
  import hashlib
9
- from ccxt.base.types import Account, Balances, Currency, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction
9
+ from ccxt.base.types import Account, Balances, Conversion, Currencies, Currency, DepositAddress, Int, LedgerEntry, Market, MarketInterface, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFees, Transaction
10
10
  from typing import List
11
11
  from ccxt.base.errors import ExchangeError
12
+ from ccxt.base.errors import AuthenticationError
13
+ from ccxt.base.errors import PermissionDenied
12
14
  from ccxt.base.errors import ArgumentsRequired
13
15
  from ccxt.base.errors import BadRequest
14
16
  from ccxt.base.errors import InvalidOrder
@@ -16,7 +18,6 @@ from ccxt.base.errors import OrderNotFound
16
18
  from ccxt.base.errors import NotSupported
17
19
  from ccxt.base.errors import RateLimitExceeded
18
20
  from ccxt.base.errors import InvalidNonce
19
- from ccxt.base.errors import AuthenticationError
20
21
  from ccxt.base.decimal_to_precision import TICK_SIZE
21
22
  from ccxt.base.precise import Precise
22
23
 
@@ -26,11 +27,12 @@ class coinbase(Exchange, ImplicitAPI):
26
27
  def describe(self):
27
28
  return self.deep_extend(super(coinbase, self).describe(), {
28
29
  'id': 'coinbase',
29
- 'name': 'Coinbase',
30
+ 'name': 'Coinbase Advanced',
30
31
  'countries': ['US'],
31
32
  'pro': True,
33
+ 'certified': True,
32
34
  # rate-limits:
33
- # ADVANCED API: https://docs.cloud.coinbase.com/advanced-trade-api/docs/rest-api-rate-limits
35
+ # ADVANCED API: https://docs.cloud.coinbase.com/advanced-trade/docs/rest-api-rate-limits
34
36
  # - max 30 req/second for private data, 10 req/s for public data
35
37
  # DATA API : https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/rate-limiting
36
38
  # - max 10000 req/hour(to prevent userland mistakes we apply ~3 req/second RL per call
@@ -51,7 +53,8 @@ class coinbase(Exchange, ImplicitAPI):
51
53
  'cancelOrder': True,
52
54
  'cancelOrders': True,
53
55
  'closeAllPositions': False,
54
- 'closePosition': False,
56
+ 'closePosition': True,
57
+ 'createConvertTrade': True,
55
58
  'createDepositAddress': True,
56
59
  'createLimitBuyOrder': True,
57
60
  'createLimitSellOrder': True,
@@ -75,6 +78,9 @@ class coinbase(Exchange, ImplicitAPI):
75
78
  'fetchBorrowRateHistory': False,
76
79
  'fetchCanceledOrders': True,
77
80
  'fetchClosedOrders': True,
81
+ 'fetchConvertQuote': True,
82
+ 'fetchConvertTrade': True,
83
+ 'fetchConvertTradeHistory': False,
78
84
  'fetchCrossBorrowRate': False,
79
85
  'fetchCrossBorrowRates': False,
80
86
  'fetchCurrencies': True,
@@ -82,7 +88,10 @@ class coinbase(Exchange, ImplicitAPI):
82
88
  'fetchDepositAddress': 'emulated',
83
89
  'fetchDepositAddresses': False,
84
90
  'fetchDepositAddressesByNetwork': True,
91
+ 'fetchDepositMethodId': True,
92
+ 'fetchDepositMethodIds': True,
85
93
  'fetchDeposits': True,
94
+ 'fetchDepositsWithdrawals': True,
86
95
  'fetchFundingHistory': False,
87
96
  'fetchFundingRate': False,
88
97
  'fetchFundingRateHistory': False,
@@ -106,17 +115,17 @@ class coinbase(Exchange, ImplicitAPI):
106
115
  'fetchOrder': True,
107
116
  'fetchOrderBook': True,
108
117
  'fetchOrders': True,
109
- 'fetchPosition': False,
118
+ 'fetchPosition': True,
110
119
  'fetchPositionMode': False,
111
- 'fetchPositions': False,
120
+ 'fetchPositions': True,
112
121
  'fetchPositionsRisk': False,
113
122
  'fetchPremiumIndexOHLCV': False,
114
123
  'fetchTicker': True,
115
124
  'fetchTickers': True,
116
125
  'fetchTime': True,
117
126
  'fetchTrades': True,
118
- 'fetchTradingFee': False,
119
- 'fetchTradingFees': False,
127
+ 'fetchTradingFee': 'emulated',
128
+ 'fetchTradingFees': True,
120
129
  'fetchWithdrawals': True,
121
130
  'reduceMargin': False,
122
131
  'setLeverage': False,
@@ -132,7 +141,7 @@ class coinbase(Exchange, ImplicitAPI):
132
141
  'www': 'https://www.coinbase.com',
133
142
  'doc': [
134
143
  'https://developers.coinbase.com/api/v2',
135
- 'https://docs.cloud.coinbase.com/advanced-trade-api/docs/welcome',
144
+ 'https://docs.cloud.coinbase.com/advanced-trade/docs/welcome',
136
145
  ],
137
146
  'fees': [
138
147
  'https://support.coinbase.com/customer/portal/articles/2109597-buy-sell-bank-transfer-fees',
@@ -210,6 +219,11 @@ class coinbase(Exchange, ImplicitAPI):
210
219
  'public': {
211
220
  'get': {
212
221
  'brokerage/time': 3,
222
+ 'brokerage/market/product_book': 3,
223
+ 'brokerage/market/products': 3,
224
+ 'brokerage/market/products/{product_id}': 3,
225
+ 'brokerage/market/products/{product_id}/candles': 3,
226
+ 'brokerage/market/products/{product_id}/ticker': 3,
213
227
  },
214
228
  },
215
229
  'private': {
@@ -251,6 +265,8 @@ class coinbase(Exchange, ImplicitAPI):
251
265
  'brokerage/convert/trade/{trade_id}': 1,
252
266
  'brokerage/cfm/sweeps/schedule': 1,
253
267
  'brokerage/intx/allocate': 1,
268
+ # futures
269
+ 'brokerage/orders/close_position': 1,
254
270
  },
255
271
  'put': {
256
272
  'brokerage/portfolios/{portfolio_uuid}': 1,
@@ -264,8 +280,8 @@ class coinbase(Exchange, ImplicitAPI):
264
280
  },
265
281
  'fees': {
266
282
  'trading': {
267
- 'taker': self.parse_number('0.006'),
268
- 'maker': self.parse_number('0.004'),
283
+ 'taker': self.parse_number('0.012'),
284
+ 'maker': self.parse_number('0.006'), # {"pricing_tier":"Advanced 1","usd_from":"0","usd_to":"1000","taker_fee_rate":"0.012","maker_fee_rate":"0.006","aop_from":"","aop_to":""}
269
285
  'tierBased': True,
270
286
  'percentage': True,
271
287
  'tiers': {
@@ -317,6 +333,8 @@ class coinbase(Exchange, ImplicitAPI):
317
333
  'internal_server_error': ExchangeError, # 500 Internal server error
318
334
  'UNSUPPORTED_ORDER_CONFIGURATION': BadRequest,
319
335
  'INSUFFICIENT_FUND': BadRequest,
336
+ 'PERMISSION_DENIED': PermissionDenied,
337
+ 'INVALID_ARGUMENT': BadRequest,
320
338
  },
321
339
  'broad': {
322
340
  'request timestamp expired': InvalidNonce, # {"errors":[{"id":"authentication_error","message":"request timestamp expired"}]}
@@ -337,6 +355,8 @@ class coinbase(Exchange, ImplicitAPI):
337
355
  'CGLD': 'CELO',
338
356
  },
339
357
  'options': {
358
+ 'usePrivate': False,
359
+ 'brokerId': 'ccxt',
340
360
  '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'],
341
361
  'fetchCurrencies': {
342
362
  'expires': 5000,
@@ -357,6 +377,8 @@ class coinbase(Exchange, ImplicitAPI):
357
377
  'createMarketBuyOrderRequiresPrice': True,
358
378
  'advanced': True, # set to True if using any v3 endpoints from the advanced trade API
359
379
  'fetchMarkets': 'fetchMarketsV3', # 'fetchMarketsV3' or 'fetchMarketsV2'
380
+ 'timeDifference': 0, # the difference between system clock and exchange server clock
381
+ 'adjustForTimeDifference': False, # controls the adjustment logic upon instantiation
360
382
  'fetchTicker': 'fetchTickerV3', # 'fetchTickerV3' or 'fetchTickerV2'
361
383
  'fetchTickers': 'fetchTickersV3', # 'fetchTickersV3' or 'fetchTickersV2'
362
384
  'fetchAccounts': 'fetchAccountsV3', # 'fetchAccountsV3' or 'fetchAccountsV2'
@@ -364,12 +386,94 @@ class coinbase(Exchange, ImplicitAPI):
364
386
  'fetchTime': 'v2PublicGetTime', # 'v2PublicGetTime' or 'v3PublicGetBrokerageTime'
365
387
  'user_native_currency': 'USD', # needed to get fees for v3
366
388
  },
389
+ 'features': {
390
+ 'default': {
391
+ 'sandbox': False,
392
+ 'createOrder': {
393
+ 'marginMode': True,
394
+ 'triggerPrice': True,
395
+ 'triggerPriceType': None,
396
+ 'triggerDirection': True,
397
+ 'stopLossPrice': True,
398
+ 'takeProfitPrice': True,
399
+ 'attachedStopLossTakeProfit': None,
400
+ 'timeInForce': {
401
+ 'IOC': True,
402
+ 'FOK': True,
403
+ 'PO': True,
404
+ 'GTD': True,
405
+ },
406
+ 'hedged': False,
407
+ 'trailing': False,
408
+ 'leverage': True, # todo implement
409
+ 'marketBuyByCost': True,
410
+ 'marketBuyRequiresPrice': True,
411
+ 'selfTradePrevention': False,
412
+ 'iceberg': False,
413
+ },
414
+ 'createOrders': None,
415
+ 'fetchMyTrades': {
416
+ 'marginMode': False,
417
+ 'limit': 3000,
418
+ 'daysBack': None,
419
+ 'untilDays': 10000,
420
+ },
421
+ 'fetchOrder': {
422
+ 'marginMode': False,
423
+ 'trigger': False,
424
+ 'trailing': False,
425
+ },
426
+ 'fetchOpenOrders': {
427
+ 'marginMode': False,
428
+ 'limit': None,
429
+ 'trigger': False,
430
+ 'trailing': False,
431
+ },
432
+ 'fetchOrders': {
433
+ 'marginMode': False,
434
+ 'limit': None,
435
+ 'daysBack': None,
436
+ 'untilDays': 10000,
437
+ 'trigger': False,
438
+ 'trailing': False,
439
+ },
440
+ 'fetchClosedOrders': {
441
+ 'marginMode': False,
442
+ 'limit': None,
443
+ 'daysBack': None,
444
+ 'daysBackCanceled': None,
445
+ 'untilDays': 10000,
446
+ 'trigger': False,
447
+ 'trailing': False,
448
+ },
449
+ 'fetchOHLCV': {
450
+ 'limit': 350,
451
+ },
452
+ },
453
+ 'spot': {
454
+ 'extends': 'default',
455
+ },
456
+ 'swap': {
457
+ 'linear': {
458
+ 'extends': 'default',
459
+ },
460
+ 'inverse': None,
461
+ },
462
+ 'future': {
463
+ 'linear': {
464
+ 'extends': 'default',
465
+ },
466
+ 'inverse': None,
467
+ },
468
+ },
367
469
  })
368
470
 
369
471
  def fetch_time(self, params={}):
370
472
  """
371
473
  fetches the current integer timestamp in milliseconds from the exchange server
372
- :see: https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-time#http-request
474
+
475
+ https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-time#http-request
476
+
373
477
  :param dict [params]: extra parameters specific to the exchange API endpoint
374
478
  :param str [params.method]: 'v2PublicGetTime' or 'v3PublicGetBrokerageTime' default is 'v2PublicGetTime'
375
479
  :returns int: the current integer timestamp in milliseconds from the exchange server
@@ -403,8 +507,10 @@ class coinbase(Exchange, ImplicitAPI):
403
507
  def fetch_accounts(self, params={}) -> List[Account]:
404
508
  """
405
509
  fetch all the accounts associated with a profile
406
- :see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getaccounts
407
- :see: https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-accounts#list-accounts
510
+
511
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_getaccounts
512
+ https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-accounts#list-accounts
513
+
408
514
  :param dict [params]: extra parameters specific to the exchange API endpoint
409
515
  :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
410
516
  :returns dict: a dictionary of `account structures <https://docs.ccxt.com/#/?id=account-structure>` indexed by the account type
@@ -420,7 +526,7 @@ class coinbase(Exchange, ImplicitAPI):
420
526
  paginate, params = self.handle_option_and_params(params, 'fetchAccounts', 'paginate')
421
527
  if paginate:
422
528
  return self.fetch_paginated_call_cursor('fetchAccounts', None, None, None, params, 'next_starting_after', 'starting_after', None, 100)
423
- request = {
529
+ request: dict = {
424
530
  'limit': 100,
425
531
  }
426
532
  response = self.v2PrivateGetAccounts(self.extend(request, params))
@@ -485,9 +591,9 @@ class coinbase(Exchange, ImplicitAPI):
485
591
  paginate = False
486
592
  paginate, params = self.handle_option_and_params(params, 'fetchAccounts', 'paginate')
487
593
  if paginate:
488
- return self.fetch_paginated_call_cursor('fetchAccounts', None, None, None, params, 'cursor', 'cursor', None, 100)
489
- request = {
490
- 'limit': 100,
594
+ return self.fetch_paginated_call_cursor('fetchAccounts', None, None, None, params, 'cursor', 'cursor', None, 250)
595
+ request: dict = {
596
+ 'limit': 250,
491
597
  }
492
598
  response = self.v3PrivateGetBrokerageAccounts(self.extend(request, params))
493
599
  #
@@ -530,6 +636,28 @@ class coinbase(Exchange, ImplicitAPI):
530
636
  accounts[lastIndex] = last
531
637
  return self.parse_accounts(accounts, params)
532
638
 
639
+ def fetch_portfolios(self, params={}) -> List[Account]:
640
+ """
641
+ fetch all the portfolios
642
+
643
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_getportfolios
644
+
645
+ :param dict [params]: extra parameters specific to the exchange API endpoint
646
+ :returns dict: a dictionary of `account structures <https://docs.ccxt.com/#/?id=account-structure>` indexed by the account type
647
+ """
648
+ response = self.v3PrivateGetBrokeragePortfolios(params)
649
+ portfolios = self.safe_list(response, 'portfolios', [])
650
+ result = []
651
+ for i in range(0, len(portfolios)):
652
+ portfolio = portfolios[i]
653
+ result.append({
654
+ 'id': self.safe_string(portfolio, 'uuid'),
655
+ 'type': self.safe_string(portfolio, 'type'),
656
+ 'code': None,
657
+ 'info': portfolio,
658
+ })
659
+ return result
660
+
533
661
  def parse_account(self, account):
534
662
  #
535
663
  # fetchAccountsV2
@@ -603,7 +731,9 @@ class coinbase(Exchange, ImplicitAPI):
603
731
  def create_deposit_address(self, code: str, params={}):
604
732
  """
605
733
  create a currency deposit address
606
- :see: https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-addresses#create-address
734
+
735
+ https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-addresses#create-address
736
+
607
737
  :param str code: unified currency code of the currency for the deposit address
608
738
  :param dict [params]: extra parameters specific to the exchange API endpoint
609
739
  :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
@@ -619,7 +749,7 @@ class coinbase(Exchange, ImplicitAPI):
619
749
  break
620
750
  if accountId is None:
621
751
  raise ExchangeError(self.id + ' createDepositAddress() could not find the account with matching currency code, specify an `account_id` extra param')
622
- request = {
752
+ request: dict = {
623
753
  'account_id': accountId,
624
754
  }
625
755
  response = self.v2PrivatePostAccountsAccountIdAddresses(self.extend(request, params))
@@ -671,9 +801,11 @@ class coinbase(Exchange, ImplicitAPI):
671
801
 
672
802
  def fetch_my_sells(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
673
803
  """
674
- * @ignore
804
+ @ignore
675
805
  fetch sells
676
- :see: https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-sells#list-sells
806
+
807
+ https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-sells#list-sells
808
+
677
809
  :param str symbol: not used by coinbase fetchMySells()
678
810
  :param int [since]: timestamp in ms of the earliest sell, default is None
679
811
  :param int [limit]: max number of sells to return, default is None
@@ -689,9 +821,11 @@ class coinbase(Exchange, ImplicitAPI):
689
821
 
690
822
  def fetch_my_buys(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
691
823
  """
692
- * @ignore
824
+ @ignore
693
825
  fetch buys
694
- :see: https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-buys#list-buys
826
+
827
+ https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-buys#list-buys
828
+
695
829
  :param str symbol: not used by coinbase fetchMyBuys()
696
830
  :param int [since]: timestamp in ms of the earliest buy, default is None
697
831
  :param int [limit]: max number of buys to return, default is None
@@ -714,39 +848,69 @@ class coinbase(Exchange, ImplicitAPI):
714
848
 
715
849
  def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
716
850
  """
717
- fetch all withdrawals made from an account
718
- :see: https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-withdrawals#list-withdrawals
851
+ Fetch all withdrawals made from an account. Won't return crypto withdrawals. Use fetchLedger for those.
852
+
853
+ https://docs.cdp.coinbase.com/coinbase-app/docs/api-withdrawals#list-withdrawals
854
+
719
855
  :param str code: unified currency code
720
856
  :param int [since]: the earliest time in ms to fetch withdrawals for
721
857
  :param int [limit]: the maximum number of withdrawals structures to retrieve
722
858
  :param dict [params]: extra parameters specific to the exchange API endpoint
859
+ :param str [params.currencyType]: "fiat" or "crypto"
723
860
  :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
724
861
  """
725
- # fiat only, for crypto transactions use fetchLedger
862
+ currencyType = None
863
+ currencyType, params = self.handle_option_and_params(params, 'fetchWithdrawals', 'currencyType')
864
+ if currencyType == 'crypto':
865
+ results = self.fetch_transactions_with_method('v2PrivateGetAccountsAccountIdTransactions', code, since, limit, params)
866
+ return self.filter_by_array(results, 'type', 'withdrawal', False)
726
867
  return self.fetch_transactions_with_method('v2PrivateGetAccountsAccountIdWithdrawals', code, since, limit, params)
727
868
 
728
869
  def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
729
870
  """
730
- fetch all deposits made to an account
731
- :see: https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-deposits#list-deposits
871
+ Fetch all fiat deposits made to an account. Won't return crypto deposits or staking rewards. Use fetchLedger for those.
872
+
873
+ https://docs.cdp.coinbase.com/coinbase-app/docs/api-deposits#list-deposits
874
+
732
875
  :param str code: unified currency code
733
876
  :param int [since]: the earliest time in ms to fetch deposits for
734
877
  :param int [limit]: the maximum number of deposits structures to retrieve
735
878
  :param dict [params]: extra parameters specific to the exchange API endpoint
879
+ :param str [params.currencyType]: "fiat" or "crypto"
736
880
  :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
737
881
  """
738
- # fiat only, for crypto transactions use fetchLedger
882
+ currencyType = None
883
+ currencyType, params = self.handle_option_and_params(params, 'fetchWithdrawals', 'currencyType')
884
+ if currencyType == 'crypto':
885
+ results = self.fetch_transactions_with_method('v2PrivateGetAccountsAccountIdTransactions', code, since, limit, params)
886
+ return self.filter_by_array(results, 'type', 'deposit', False)
739
887
  return self.fetch_transactions_with_method('v2PrivateGetAccountsAccountIdDeposits', code, since, limit, params)
740
888
 
741
- def parse_transaction_status(self, status):
742
- statuses = {
889
+ def fetch_deposits_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
890
+ """
891
+ fetch history of deposits and withdrawals
892
+
893
+ https://docs.cdp.coinbase.com/coinbase-app/docs/api-transactions
894
+
895
+ :param str [code]: unified currency code for the currency of the deposit/withdrawals, default is None
896
+ :param int [since]: timestamp in ms of the earliest deposit/withdrawal, default is None
897
+ :param int [limit]: max number of deposit/withdrawals to return, default = 50, Min: 1, Max: 100
898
+ :param dict [params]: extra parameters specific to the exchange API endpoint
899
+ :returns dict: a list of `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
900
+ """
901
+ self.load_markets()
902
+ results = self.fetch_transactions_with_method('v2PrivateGetAccountsAccountIdTransactions', code, since, limit, params)
903
+ return self.filter_by_array(results, 'type', ['deposit', 'withdrawal'], False)
904
+
905
+ def parse_transaction_status(self, status: Str):
906
+ statuses: dict = {
743
907
  'created': 'pending',
744
908
  'completed': 'ok',
745
909
  'canceled': 'canceled',
746
910
  }
747
911
  return self.safe_string(statuses, status, status)
748
912
 
749
- def parse_transaction(self, transaction, currency: Currency = None) -> Transaction:
913
+ def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
750
914
  #
751
915
  # fiat deposit
752
916
  #
@@ -861,16 +1025,59 @@ class coinbase(Exchange, ImplicitAPI):
861
1025
  # "hide_native_amount": False
862
1026
  # }
863
1027
  #
1028
+ #
1029
+ # crypto deposit & withdrawal(using `/transactions` endpoint)
1030
+ # {
1031
+ # "amount": {
1032
+ # "amount": "0.00014200",(negative for withdrawal)
1033
+ # "currency": "BTC"
1034
+ # },
1035
+ # "created_at": "2024-03-29T15:48:30Z",
1036
+ # "id": "0031a605-241d-514d-a97b-d4b99f3225d3",
1037
+ # "idem": "092a979b-017e-4403-940a-2ca57811f442", # field present only in case of withdrawal
1038
+ # "native_amount": {
1039
+ # "amount": "9.85",(negative for withdrawal)
1040
+ # "currency": "USD"
1041
+ # },
1042
+ # "network": {
1043
+ # "status": "pending", # if status is `off_blockchain` then no more other fields are hasattr(self, present) object
1044
+ # "hash": "5jYuvrNsvX2DZoMnzGYzVpYxJLfYu4GSK3xetG1H5LHrSovsuFCFYdFMwNRoiht3s6fBk92MM8QLLnz65xuEFTrE",
1045
+ # "network_name": "solana",
1046
+ # "transaction_fee": {
1047
+ # "amount": "0.000100000",
1048
+ # "currency": "SOL"
1049
+ # }
1050
+ # },
1051
+ # "resource": "transaction",
1052
+ # "resource_path": "/v2/accounts/dc504b1c-248e-5b68-a3b0-b991f7fa84e6/transactions/0031a605-241d-514d-a97b-d4b99f3225d3",
1053
+ # "status": "completed",
1054
+ # "type": "send",
1055
+ # "from": { # in some cases, field might be present for deposit
1056
+ # "id": "7fd10cd7-b091-5cee-ba41-c29e49a7cccf",
1057
+ # "name": "Coinbase",
1058
+ # "resource": "user"
1059
+ # },
1060
+ # "to": { # field only present for withdrawal
1061
+ # "address": "5HA12BNthAvBwNYARYf9y5MqqCpB4qhCNFCs1Qw48ACE",
1062
+ # "resource": "address"
1063
+ # },
1064
+ # "description": "C3 - One Time BTC Credit . Reference Case # 123.", # in some cases, field might be present for deposit
1065
+ # }
1066
+ #
864
1067
  transactionType = self.safe_string(transaction, 'type')
865
1068
  amountAndCurrencyObject = None
866
1069
  feeObject = None
1070
+ network = self.safe_dict(transaction, 'network', {})
867
1071
  if transactionType == 'send':
868
- network = self.safe_dict(transaction, 'network', {})
869
- amountAndCurrencyObject = self.safe_dict(network, 'transaction_amount', {})
1072
+ amountAndCurrencyObject = self.safe_dict(network, 'transaction_amount')
870
1073
  feeObject = self.safe_dict(network, 'transaction_fee', {})
871
1074
  else:
872
- amountAndCurrencyObject = self.safe_dict(transaction, 'subtotal', {})
1075
+ amountAndCurrencyObject = self.safe_dict(transaction, 'subtotal')
873
1076
  feeObject = self.safe_dict(transaction, 'fee', {})
1077
+ if amountAndCurrencyObject is None:
1078
+ amountAndCurrencyObject = self.safe_dict(transaction, 'amount')
1079
+ amountString = self.safe_string(amountAndCurrencyObject, 'amount')
1080
+ amountStringAbs = Precise.string_abs(amountString)
874
1081
  status = self.parse_transaction_status(self.safe_string(transaction, 'status'))
875
1082
  if status is None:
876
1083
  committed = self.safe_bool(transaction, 'committed')
@@ -879,23 +1086,31 @@ class coinbase(Exchange, ImplicitAPI):
879
1086
  currencyId = self.safe_string(amountAndCurrencyObject, 'currency')
880
1087
  feeCurrencyId = self.safe_string(feeObject, 'currency')
881
1088
  datetime = self.safe_string(transaction, 'created_at')
882
- toObject = self.safe_dict(transaction, 'to', {})
883
- toAddress = self.safe_string(toObject, 'address')
1089
+ resource = self.safe_string(transaction, 'resource')
1090
+ type = resource
1091
+ if not self.in_array(type, ['deposit', 'withdrawal']):
1092
+ if Precise.string_gt(amountString, '0'):
1093
+ type = 'deposit'
1094
+ elif Precise.string_lt(amountString, '0'):
1095
+ type = 'withdrawal'
1096
+ toObject = self.safe_dict(transaction, 'to')
1097
+ addressTo = self.safe_string(toObject, 'address')
1098
+ networkId = self.safe_string(network, 'network_name')
884
1099
  return {
885
1100
  'info': transaction,
886
1101
  'id': id,
887
- 'txid': id,
1102
+ 'txid': self.safe_string(network, 'hash', id),
888
1103
  'timestamp': self.parse8601(datetime),
889
1104
  'datetime': datetime,
890
- 'network': None,
891
- 'address': toAddress,
892
- 'addressTo': toAddress,
1105
+ 'network': self.network_id_to_code(networkId),
1106
+ 'address': addressTo,
1107
+ 'addressTo': addressTo,
893
1108
  'addressFrom': None,
894
1109
  'tag': None,
895
1110
  'tagTo': None,
896
1111
  'tagFrom': None,
897
- 'type': self.safe_string(transaction, 'resource'),
898
- 'amount': self.safe_number(amountAndCurrencyObject, 'amount'),
1112
+ 'type': type,
1113
+ 'amount': self.parse_number(amountStringAbs),
899
1114
  'currency': self.safe_currency_code(currencyId, currency),
900
1115
  'status': status,
901
1116
  'updated': self.parse8601(self.safe_string(transaction, 'updated_at')),
@@ -905,7 +1120,7 @@ class coinbase(Exchange, ImplicitAPI):
905
1120
  },
906
1121
  }
907
1122
 
908
- def parse_trade(self, trade, market: Market = None) -> Trade:
1123
+ def parse_trade(self, trade: dict, market: Market = None) -> Trade:
909
1124
  #
910
1125
  # fetchMyBuys, fetchMySells
911
1126
  #
@@ -1030,17 +1245,24 @@ class coinbase(Exchange, ImplicitAPI):
1030
1245
  },
1031
1246
  })
1032
1247
 
1033
- def fetch_markets(self, params={}):
1248
+ def fetch_markets(self, params={}) -> List[Market]:
1034
1249
  """
1035
- :see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getproducts
1036
- :see: https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-currencies#get-fiat-currencies
1037
- :see: https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-exchange-rates#get-exchange-rates
1250
+
1251
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_getpublicproducts
1252
+ https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-currencies#get-fiat-currencies
1253
+ https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-exchange-rates#get-exchange-rates
1254
+
1038
1255
  retrieves data on all markets for coinbase
1039
1256
  :param dict [params]: extra parameters specific to the exchange API endpoint
1257
+ :param boolean [params.usePrivate]: use private endpoint for fetching markets
1040
1258
  :returns dict[]: an array of objects representing market data
1041
1259
  """
1260
+ if self.options['adjustForTimeDifference']:
1261
+ self.load_time_difference()
1042
1262
  method = self.safe_string(self.options, 'fetchMarkets', 'fetchMarketsV3')
1043
- return getattr(self, method)(params)
1263
+ if method == 'fetchMarketsV3':
1264
+ return self.fetch_markets_v3(params)
1265
+ return self.fetch_markets_v2(params)
1044
1266
 
1045
1267
  def fetch_markets_v2(self, params={}):
1046
1268
  response = self.fetch_currencies_from_cache(params)
@@ -1112,9 +1334,142 @@ class coinbase(Exchange, ImplicitAPI):
1112
1334
  return result
1113
1335
 
1114
1336
  def fetch_markets_v3(self, params={}):
1115
- response = self.v3PrivateGetBrokerageProducts(params)
1337
+ usePrivate = False
1338
+ usePrivate, params = self.handle_option_and_params(params, 'fetchMarkets', 'usePrivate', False)
1339
+ spotUnresolvedPromises = []
1340
+ if usePrivate:
1341
+ spotUnresolvedPromises.append(self.v3PrivateGetBrokerageProducts(params))
1342
+ else:
1343
+ spotUnresolvedPromises.append(self.v3PublicGetBrokerageMarketProducts(params))
1344
+ #
1345
+ # {
1346
+ # products: [
1347
+ # {
1348
+ # product_id: 'BTC-USD',
1349
+ # price: '67060',
1350
+ # price_percentage_change_24h: '3.30054960636883',
1351
+ # volume_24h: '10967.87426597',
1352
+ # volume_percentage_change_24h: '141.73048325503036',
1353
+ # base_increment: '0.00000001',
1354
+ # quote_increment: '0.01',
1355
+ # quote_min_size: '1',
1356
+ # quote_max_size: '150000000',
1357
+ # base_min_size: '0.00000001',
1358
+ # base_max_size: '3400',
1359
+ # base_name: 'Bitcoin',
1360
+ # quote_name: 'US Dollar',
1361
+ # watched: False,
1362
+ # is_disabled: False,
1363
+ # new: False,
1364
+ # status: 'online',
1365
+ # cancel_only: False,
1366
+ # limit_only: False,
1367
+ # post_only: False,
1368
+ # trading_disabled: False,
1369
+ # auction_mode: False,
1370
+ # product_type: 'SPOT',
1371
+ # quote_currency_id: 'USD',
1372
+ # base_currency_id: 'BTC',
1373
+ # fcm_trading_session_details: null,
1374
+ # mid_market_price: '',
1375
+ # alias: '',
1376
+ # alias_to: ['BTC-USDC'],
1377
+ # base_display_symbol: 'BTC',
1378
+ # quote_display_symbol: 'USD',
1379
+ # view_only: False,
1380
+ # price_increment: '0.01',
1381
+ # display_name: 'BTC-USD',
1382
+ # product_venue: 'CBE'
1383
+ # },
1384
+ # ...
1385
+ # ],
1386
+ # num_products: '646'
1387
+ # }
1388
+ #
1389
+ if self.check_required_credentials(False):
1390
+ spotUnresolvedPromises.append(self.v3PrivateGetBrokerageTransactionSummary(params))
1391
+ #
1392
+ # {
1393
+ # total_volume: '9.995989116664404',
1394
+ # total_fees: '0.07996791093331522',
1395
+ # fee_tier: {
1396
+ # pricing_tier: 'Advanced 1',
1397
+ # usd_from: '0',
1398
+ # usd_to: '1000',
1399
+ # taker_fee_rate: '0.008',
1400
+ # maker_fee_rate: '0.006',
1401
+ # aop_from: '',
1402
+ # aop_to: ''
1403
+ # },
1404
+ # margin_rate: null,
1405
+ # goods_and_services_tax: null,
1406
+ # advanced_trade_only_volume: '9.995989116664404',
1407
+ # advanced_trade_only_fees: '0.07996791093331522',
1408
+ # coinbase_pro_volume: '0',
1409
+ # coinbase_pro_fees: '0',
1410
+ # total_balance: '',
1411
+ # has_promo_fee: False
1412
+ # }
1413
+ #
1414
+ unresolvedContractPromises = []
1415
+ try:
1416
+ unresolvedContractPromises = [
1417
+ self.v3PublicGetBrokerageMarketProducts(self.extend(params, {'product_type': 'FUTURE'})),
1418
+ self.v3PublicGetBrokerageMarketProducts(self.extend(params, {'product_type': 'FUTURE', 'contract_expiry_type': 'PERPETUAL'})),
1419
+ ]
1420
+ if self.check_required_credentials(False):
1421
+ unresolvedContractPromises.append(self.extend(params, {'product_type': 'FUTURE'}))
1422
+ unresolvedContractPromises.append(self.extend(params, {'product_type': 'FUTURE', 'contract_expiry_type': 'PERPETUAL'}))
1423
+ except Exception as e:
1424
+ unresolvedContractPromises = [] # the sync version of ccxt won't have the promise.all line so the request is made here. Some users can't access perpetual products
1425
+ promises = spotUnresolvedPromises
1426
+ contractPromises = None
1427
+ try:
1428
+ contractPromises = unresolvedContractPromises # some users don't have access to contracts
1429
+ except Exception as e:
1430
+ contractPromises = []
1431
+ spot = self.safe_dict(promises, 0, {})
1432
+ fees = self.safe_dict(promises, 1, {})
1433
+ expiringFutures = self.safe_dict(contractPromises, 0, {})
1434
+ perpetualFutures = self.safe_dict(contractPromises, 1, {})
1435
+ expiringFees = self.safe_dict(contractPromises, 2, {})
1436
+ perpetualFees = self.safe_dict(contractPromises, 3, {})
1437
+ #
1438
+ # {
1439
+ # "total_volume": 0,
1440
+ # "total_fees": 0,
1441
+ # "fee_tier": {
1442
+ # "pricing_tier": "",
1443
+ # "usd_from": "0",
1444
+ # "usd_to": "10000",
1445
+ # "taker_fee_rate": "0.006",
1446
+ # "maker_fee_rate": "0.004"
1447
+ # },
1448
+ # "margin_rate": null,
1449
+ # "goods_and_services_tax": null,
1450
+ # "advanced_trade_only_volume": 0,
1451
+ # "advanced_trade_only_fees": 0,
1452
+ # "coinbase_pro_volume": 0,
1453
+ # "coinbase_pro_fees": 0
1454
+ # }
1455
+ #
1456
+ feeTier = self.safe_dict(fees, 'fee_tier', {})
1457
+ expiringFeeTier = self.safe_dict(expiringFees, 'fee_tier', {}) # fee tier null?
1458
+ perpetualFeeTier = self.safe_dict(perpetualFees, 'fee_tier', {}) # fee tier null?
1459
+ data = self.safe_list(spot, 'products', [])
1460
+ result = []
1461
+ for i in range(0, len(data)):
1462
+ result.append(self.parse_spot_market(data[i], feeTier))
1463
+ futureData = self.safe_list(expiringFutures, 'products', [])
1464
+ for i in range(0, len(futureData)):
1465
+ result.append(self.parse_contract_market(futureData[i], expiringFeeTier))
1466
+ perpetualData = self.safe_list(perpetualFutures, 'products', [])
1467
+ for i in range(0, len(perpetualData)):
1468
+ result.append(self.parse_contract_market(perpetualData[i], perpetualFeeTier))
1469
+ return result
1470
+
1471
+ def parse_spot_market(self, market, feeTier) -> MarketInterface:
1116
1472
  #
1117
- # [
1118
1473
  # {
1119
1474
  # "product_id": "TONE-USD",
1120
1475
  # "price": "0.01523",
@@ -1143,95 +1498,266 @@ class coinbase(Exchange, ImplicitAPI):
1143
1498
  # "base_currency_id": "TONE",
1144
1499
  # "fcm_trading_session_details": null,
1145
1500
  # "mid_market_price": ""
1146
- # },
1147
- # ...
1148
- # ]
1501
+ # }
1149
1502
  #
1150
- fees = self.v3PrivateGetBrokerageTransactionSummary(params)
1503
+ id = self.safe_string(market, 'product_id')
1504
+ baseId = self.safe_string(market, 'base_currency_id')
1505
+ quoteId = self.safe_string(market, 'quote_currency_id')
1506
+ base = self.safe_currency_code(baseId)
1507
+ quote = self.safe_currency_code(quoteId)
1508
+ marketType = self.safe_string_lower(market, 'product_type')
1509
+ tradingDisabled = self.safe_bool(market, 'trading_disabled')
1510
+ stablePairs = self.safe_list(self.options, 'stablePairs', [])
1511
+ defaultTakerFee = self.safe_number(self.fees['trading'], 'taker')
1512
+ defaultMakerFee = self.safe_number(self.fees['trading'], 'maker')
1513
+ takerFee = 0.00001 if self.in_array(id, stablePairs) else self.safe_number(feeTier, 'taker_fee_rate', defaultTakerFee)
1514
+ makerFee = 0.0 if self.in_array(id, stablePairs) else self.safe_number(feeTier, 'maker_fee_rate', defaultMakerFee)
1515
+ return self.safe_market_structure({
1516
+ 'id': id,
1517
+ 'symbol': base + '/' + quote,
1518
+ 'base': base,
1519
+ 'quote': quote,
1520
+ 'settle': None,
1521
+ 'baseId': baseId,
1522
+ 'quoteId': quoteId,
1523
+ 'settleId': None,
1524
+ 'type': marketType,
1525
+ 'spot': (marketType == 'spot'),
1526
+ 'margin': None,
1527
+ 'swap': False,
1528
+ 'future': False,
1529
+ 'option': False,
1530
+ 'active': not tradingDisabled,
1531
+ 'contract': False,
1532
+ 'linear': None,
1533
+ 'inverse': None,
1534
+ 'taker': takerFee,
1535
+ 'maker': makerFee,
1536
+ 'contractSize': None,
1537
+ 'expiry': None,
1538
+ 'expiryDatetime': None,
1539
+ 'strike': None,
1540
+ 'optionType': None,
1541
+ 'precision': {
1542
+ 'amount': self.safe_number(market, 'base_increment'),
1543
+ 'price': self.safe_number_2(market, 'price_increment', 'quote_increment'),
1544
+ },
1545
+ 'limits': {
1546
+ 'leverage': {
1547
+ 'min': None,
1548
+ 'max': None,
1549
+ },
1550
+ 'amount': {
1551
+ 'min': self.safe_number(market, 'base_min_size'),
1552
+ 'max': self.safe_number(market, 'base_max_size'),
1553
+ },
1554
+ 'price': {
1555
+ 'min': None,
1556
+ 'max': None,
1557
+ },
1558
+ 'cost': {
1559
+ 'min': self.safe_number(market, 'quote_min_size'),
1560
+ 'max': self.safe_number(market, 'quote_max_size'),
1561
+ },
1562
+ },
1563
+ 'created': None,
1564
+ 'info': market,
1565
+ })
1566
+
1567
+ def parse_contract_market(self, market, feeTier) -> MarketInterface:
1568
+ # expiring
1151
1569
  #
1152
- # {
1153
- # "total_volume": 0,
1154
- # "total_fees": 0,
1155
- # "fee_tier": {
1156
- # "pricing_tier": "",
1157
- # "usd_from": "0",
1158
- # "usd_to": "10000",
1159
- # "taker_fee_rate": "0.006",
1160
- # "maker_fee_rate": "0.004"
1161
- # },
1162
- # "margin_rate": null,
1163
- # "goods_and_services_tax": null,
1164
- # "advanced_trade_only_volume": 0,
1165
- # "advanced_trade_only_fees": 0,
1166
- # "coinbase_pro_volume": 0,
1167
- # "coinbase_pro_fees": 0
1168
- # }
1570
+ # {
1571
+ # "product_id":"BIT-26APR24-CDE",
1572
+ # "price":"71145",
1573
+ # "price_percentage_change_24h":"-2.36722931247427",
1574
+ # "volume_24h":"108549",
1575
+ # "volume_percentage_change_24h":"155.78255337197794",
1576
+ # "base_increment":"1",
1577
+ # "quote_increment":"0.01",
1578
+ # "quote_min_size":"0",
1579
+ # "quote_max_size":"100000000",
1580
+ # "base_min_size":"1",
1581
+ # "base_max_size":"100000000",
1582
+ # "base_name":"",
1583
+ # "quote_name":"US Dollar",
1584
+ # "watched":false,
1585
+ # "is_disabled":false,
1586
+ # "new":false,
1587
+ # "status":"",
1588
+ # "cancel_only":false,
1589
+ # "limit_only":false,
1590
+ # "post_only":false,
1591
+ # "trading_disabled":false,
1592
+ # "auction_mode":false,
1593
+ # "product_type":"FUTURE",
1594
+ # "quote_currency_id":"USD",
1595
+ # "base_currency_id":"",
1596
+ # "fcm_trading_session_details":{
1597
+ # "is_session_open":true,
1598
+ # "open_time":"2024-04-08T22:00:00Z",
1599
+ # "close_time":"2024-04-09T21:00:00Z"
1600
+ # },
1601
+ # "mid_market_price":"71105",
1602
+ # "alias":"",
1603
+ # "alias_to":[
1604
+ # ],
1605
+ # "base_display_symbol":"",
1606
+ # "quote_display_symbol":"USD",
1607
+ # "view_only":false,
1608
+ # "price_increment":"5",
1609
+ # "display_name":"BTC 26 APR 24",
1610
+ # "product_venue":"FCM",
1611
+ # "future_product_details":{
1612
+ # "venue":"cde",
1613
+ # "contract_code":"BIT",
1614
+ # "contract_expiry":"2024-04-26T15:00:00Z",
1615
+ # "contract_size":"0.01",
1616
+ # "contract_root_unit":"BTC",
1617
+ # "group_description":"Nano Bitcoin Futures",
1618
+ # "contract_expiry_timezone":"Europe/London",
1619
+ # "group_short_description":"Nano BTC",
1620
+ # "risk_managed_by":"MANAGED_BY_FCM",
1621
+ # "contract_expiry_type":"EXPIRING",
1622
+ # "contract_display_name":"BTC 26 APR 24"
1623
+ # }
1624
+ # }
1169
1625
  #
1170
- feeTier = self.safe_dict(fees, 'fee_tier', {})
1171
- data = self.safe_list(response, 'products', [])
1172
- result = []
1173
- for i in range(0, len(data)):
1174
- market = data[i]
1175
- id = self.safe_string(market, 'product_id')
1176
- baseId = self.safe_string(market, 'base_currency_id')
1177
- quoteId = self.safe_string(market, 'quote_currency_id')
1178
- base = self.safe_currency_code(baseId)
1179
- quote = self.safe_currency_code(quoteId)
1180
- marketType = self.safe_string_lower(market, 'product_type')
1181
- tradingDisabled = self.safe_bool(market, 'trading_disabled')
1182
- stablePairs = self.safe_list(self.options, 'stablePairs', [])
1183
- result.append({
1184
- 'id': id,
1185
- 'symbol': base + '/' + quote,
1186
- 'base': base,
1187
- 'quote': quote,
1188
- 'settle': None,
1189
- 'baseId': baseId,
1190
- 'quoteId': quoteId,
1191
- 'settleId': None,
1192
- 'type': marketType,
1193
- 'spot': (marketType == 'spot'),
1194
- 'margin': None,
1195
- 'swap': False,
1196
- 'future': False,
1197
- 'option': False,
1198
- 'active': not tradingDisabled,
1199
- 'contract': False,
1200
- 'linear': None,
1201
- 'inverse': None,
1202
- 'taker': 0.00001 if self.in_array(id, stablePairs) else self.safe_number(feeTier, 'taker_fee_rate'),
1203
- 'maker': 0.0 if self.in_array(id, stablePairs) else self.safe_number(feeTier, 'maker_fee_rate'),
1204
- 'contractSize': None,
1205
- 'expiry': None,
1206
- 'expiryDatetime': None,
1207
- 'strike': None,
1208
- 'optionType': None,
1209
- 'precision': {
1210
- 'amount': self.safe_number(market, 'base_increment'),
1211
- 'price': self.safe_number_2(market, 'price_increment', 'quote_increment'),
1626
+ # perpetual
1627
+ #
1628
+ # {
1629
+ # "product_id":"ETH-PERP-INTX",
1630
+ # "price":"3630.98",
1631
+ # "price_percentage_change_24h":"0.65142426292038",
1632
+ # "volume_24h":"114020.1501",
1633
+ # "volume_percentage_change_24h":"63.33650787154869",
1634
+ # "base_increment":"0.0001",
1635
+ # "quote_increment":"0.01",
1636
+ # "quote_min_size":"10",
1637
+ # "quote_max_size":"50000000",
1638
+ # "base_min_size":"0.0001",
1639
+ # "base_max_size":"50000",
1640
+ # "base_name":"",
1641
+ # "quote_name":"USDC",
1642
+ # "watched":false,
1643
+ # "is_disabled":false,
1644
+ # "new":false,
1645
+ # "status":"",
1646
+ # "cancel_only":false,
1647
+ # "limit_only":false,
1648
+ # "post_only":false,
1649
+ # "trading_disabled":false,
1650
+ # "auction_mode":false,
1651
+ # "product_type":"FUTURE",
1652
+ # "quote_currency_id":"USDC",
1653
+ # "base_currency_id":"",
1654
+ # "fcm_trading_session_details":null,
1655
+ # "mid_market_price":"3630.975",
1656
+ # "alias":"",
1657
+ # "alias_to":[],
1658
+ # "base_display_symbol":"",
1659
+ # "quote_display_symbol":"USDC",
1660
+ # "view_only":false,
1661
+ # "price_increment":"0.01",
1662
+ # "display_name":"ETH PERP",
1663
+ # "product_venue":"INTX",
1664
+ # "future_product_details":{
1665
+ # "venue":"",
1666
+ # "contract_code":"ETH",
1667
+ # "contract_expiry":null,
1668
+ # "contract_size":"1",
1669
+ # "contract_root_unit":"ETH",
1670
+ # "group_description":"",
1671
+ # "contract_expiry_timezone":"",
1672
+ # "group_short_description":"",
1673
+ # "risk_managed_by":"MANAGED_BY_VENUE",
1674
+ # "contract_expiry_type":"PERPETUAL",
1675
+ # "perpetual_details":{
1676
+ # "open_interest":"0",
1677
+ # "funding_rate":"0.000016",
1678
+ # "funding_time":"2024-04-09T09:00:00.000008Z",
1679
+ # "max_leverage":"10"
1680
+ # },
1681
+ # "contract_display_name":"ETH PERPETUAL"
1682
+ # }
1683
+ # }
1684
+ #
1685
+ id = self.safe_string(market, 'product_id')
1686
+ futureProductDetails = self.safe_dict(market, 'future_product_details', {})
1687
+ contractExpiryType = self.safe_string(futureProductDetails, 'contract_expiry_type')
1688
+ contractSize = self.safe_number(futureProductDetails, 'contract_size')
1689
+ contractExpire = self.safe_string(futureProductDetails, 'contract_expiry')
1690
+ expireTimestamp = self.parse8601(contractExpire)
1691
+ expireDateTime = self.iso8601(expireTimestamp)
1692
+ isSwap = (contractExpiryType == 'PERPETUAL')
1693
+ baseId = self.safe_string(futureProductDetails, 'contract_root_unit')
1694
+ quoteId = self.safe_string(market, 'quote_currency_id')
1695
+ base = self.safe_currency_code(baseId)
1696
+ quote = self.safe_currency_code(quoteId)
1697
+ tradingDisabled = self.safe_bool(market, 'is_disabled')
1698
+ symbol = base + '/' + quote
1699
+ type = None
1700
+ if isSwap:
1701
+ type = 'swap'
1702
+ symbol = symbol + ':' + quote
1703
+ else:
1704
+ type = 'future'
1705
+ symbol = symbol + ':' + quote + '-' + self.yymmdd(expireTimestamp)
1706
+ takerFeeRate = self.safe_number(feeTier, 'taker_fee_rate')
1707
+ makerFeeRate = self.safe_number(feeTier, 'maker_fee_rate')
1708
+ taker = takerFeeRate if takerFeeRate else self.parse_number('0.06')
1709
+ maker = makerFeeRate if makerFeeRate else self.parse_number('0.04')
1710
+ return self.safe_market_structure({
1711
+ 'id': id,
1712
+ 'symbol': symbol,
1713
+ 'base': base,
1714
+ 'quote': quote,
1715
+ 'settle': quote,
1716
+ 'baseId': baseId,
1717
+ 'quoteId': quoteId,
1718
+ 'settleId': quoteId,
1719
+ 'type': type,
1720
+ 'spot': False,
1721
+ 'margin': False,
1722
+ 'swap': isSwap,
1723
+ 'future': not isSwap,
1724
+ 'option': False,
1725
+ 'active': not tradingDisabled,
1726
+ 'contract': True,
1727
+ 'linear': True,
1728
+ 'inverse': False,
1729
+ 'taker': taker,
1730
+ 'maker': maker,
1731
+ 'contractSize': contractSize,
1732
+ 'expiry': expireTimestamp,
1733
+ 'expiryDatetime': expireDateTime,
1734
+ 'strike': None,
1735
+ 'optionType': None,
1736
+ 'precision': {
1737
+ 'amount': self.safe_number(market, 'base_increment'),
1738
+ 'price': self.safe_number_2(market, 'price_increment', 'quote_increment'),
1739
+ },
1740
+ 'limits': {
1741
+ 'leverage': {
1742
+ 'min': None,
1743
+ 'max': None,
1212
1744
  },
1213
- 'limits': {
1214
- 'leverage': {
1215
- 'min': None,
1216
- 'max': None,
1217
- },
1218
- 'amount': {
1219
- 'min': self.safe_number(market, 'base_min_size'),
1220
- 'max': self.safe_number(market, 'base_max_size'),
1221
- },
1222
- 'price': {
1223
- 'min': None,
1224
- 'max': None,
1225
- },
1226
- 'cost': {
1227
- 'min': self.safe_number(market, 'quote_min_size'),
1228
- 'max': self.safe_number(market, 'quote_max_size'),
1229
- },
1745
+ 'amount': {
1746
+ 'min': self.safe_number(market, 'base_min_size'),
1747
+ 'max': self.safe_number(market, 'base_max_size'),
1230
1748
  },
1231
- 'created': None,
1232
- 'info': market,
1233
- })
1234
- return result
1749
+ 'price': {
1750
+ 'min': None,
1751
+ 'max': None,
1752
+ },
1753
+ 'cost': {
1754
+ 'min': self.safe_number(market, 'quote_min_size'),
1755
+ 'max': self.safe_number(market, 'quote_max_size'),
1756
+ },
1757
+ },
1758
+ 'created': None,
1759
+ 'info': market,
1760
+ })
1235
1761
 
1236
1762
  def fetch_currencies_from_cache(self, params={}):
1237
1763
  options = self.safe_dict(self.options, 'fetchCurrencies', {})
@@ -1278,11 +1804,13 @@ class coinbase(Exchange, ImplicitAPI):
1278
1804
  })
1279
1805
  return self.safe_dict(self.options, 'fetchCurrencies', {})
1280
1806
 
1281
- def fetch_currencies(self, params={}):
1807
+ def fetch_currencies(self, params={}) -> Currencies:
1282
1808
  """
1283
1809
  fetches all available currencies on an exchange
1284
- :see: https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-currencies#get-fiat-currencies
1285
- :see: https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-exchange-rates#get-exchange-rates
1810
+
1811
+ https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-currencies#get-fiat-currencies
1812
+ https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-exchange-rates#get-exchange-rates
1813
+
1286
1814
  :param dict [params]: extra parameters specific to the exchange API endpoint
1287
1815
  :returns dict: an associative dictionary of currencies
1288
1816
  """
@@ -1325,9 +1853,9 @@ class coinbase(Exchange, ImplicitAPI):
1325
1853
  # }
1326
1854
  # }
1327
1855
  #
1328
- result = {}
1329
- networks = {}
1330
- networksById = {}
1856
+ result: dict = {}
1857
+ networks: dict = {}
1858
+ networksById: dict = {}
1331
1859
  for i in range(0, len(currencies)):
1332
1860
  currency = currencies[i]
1333
1861
  assetId = self.safe_string(currency, 'asset_id')
@@ -1369,10 +1897,13 @@ class coinbase(Exchange, ImplicitAPI):
1369
1897
  def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
1370
1898
  """
1371
1899
  fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
1372
- :see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getproducts
1373
- :see: https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-exchange-rates#get-exchange-rates
1900
+
1901
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_getproducts
1902
+ https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-exchange-rates#get-exchange-rates
1903
+
1374
1904
  :param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1375
1905
  :param dict [params]: extra parameters specific to the exchange API endpoint
1906
+ :param boolean [params.usePrivate]: use private endpoint for fetching tickers
1376
1907
  :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
1377
1908
  """
1378
1909
  method = self.safe_string(self.options, 'fetchTickers', 'fetchTickersV3')
@@ -1383,7 +1914,7 @@ class coinbase(Exchange, ImplicitAPI):
1383
1914
  def fetch_tickers_v2(self, symbols: Strings = None, params={}):
1384
1915
  self.load_markets()
1385
1916
  symbols = self.market_symbols(symbols)
1386
- request = {
1917
+ request: dict = {
1387
1918
  # 'currency': 'USD',
1388
1919
  }
1389
1920
  response = self.v2PublicGetExchangeRates(self.extend(request, params))
@@ -1402,7 +1933,7 @@ class coinbase(Exchange, ImplicitAPI):
1402
1933
  data = self.safe_dict(response, 'data', {})
1403
1934
  rates = self.safe_dict(data, 'rates', {})
1404
1935
  quoteId = self.safe_string(data, 'currency')
1405
- result = {}
1936
+ result: dict = {}
1406
1937
  baseIds = list(rates.keys())
1407
1938
  delimiter = '-'
1408
1939
  for i in range(0, len(baseIds)):
@@ -1416,10 +1947,20 @@ class coinbase(Exchange, ImplicitAPI):
1416
1947
  def fetch_tickers_v3(self, symbols: Strings = None, params={}):
1417
1948
  self.load_markets()
1418
1949
  symbols = self.market_symbols(symbols)
1419
- request = {}
1950
+ request: dict = {}
1420
1951
  if symbols is not None:
1421
1952
  request['product_ids'] = self.market_ids(symbols)
1422
- response = self.v3PrivateGetBrokerageProducts(self.extend(request, params))
1953
+ marketType = None
1954
+ marketType, params = self.handle_market_type_and_params('fetchTickers', self.get_market_from_symbols(symbols), params, 'default')
1955
+ if marketType is not None and marketType != 'default':
1956
+ request['product_type'] = 'FUTURE' if (marketType == 'swap') else 'SPOT'
1957
+ response = None
1958
+ usePrivate = False
1959
+ usePrivate, params = self.handle_option_and_params(params, 'fetchTickers', 'usePrivate', False)
1960
+ if usePrivate:
1961
+ response = self.v3PrivateGetBrokerageProducts(self.extend(request, params))
1962
+ else:
1963
+ response = self.v3PublicGetBrokerageMarketProducts(self.extend(request, params))
1423
1964
  #
1424
1965
  # {
1425
1966
  # "products": [
@@ -1458,7 +1999,7 @@ class coinbase(Exchange, ImplicitAPI):
1458
1999
  # }
1459
2000
  #
1460
2001
  data = self.safe_list(response, 'products', [])
1461
- result = {}
2002
+ result: dict = {}
1462
2003
  for i in range(0, len(data)):
1463
2004
  entry = data[i]
1464
2005
  marketId = self.safe_string(entry, 'product_id')
@@ -1470,12 +2011,15 @@ class coinbase(Exchange, ImplicitAPI):
1470
2011
  def fetch_ticker(self, symbol: str, params={}) -> Ticker:
1471
2012
  """
1472
2013
  fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
1473
- :see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getmarkettrades
1474
- :see: https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-prices#get-spot-price
1475
- :see: https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-prices#get-buy-price
1476
- :see: https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-prices#get-sell-price
2014
+
2015
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_getmarkettrades
2016
+ https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-prices#get-spot-price
2017
+ https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-prices#get-buy-price
2018
+ https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-prices#get-sell-price
2019
+
1477
2020
  :param str symbol: unified symbol of the market to fetch the ticker for
1478
2021
  :param dict [params]: extra parameters specific to the exchange API endpoint
2022
+ :param boolean [params.usePrivate]: whether to use the private endpoint for fetching the ticker
1479
2023
  :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
1480
2024
  """
1481
2025
  method = self.safe_string(self.options, 'fetchTicker', 'fetchTickerV3')
@@ -1504,7 +2048,7 @@ class coinbase(Exchange, ImplicitAPI):
1504
2048
  spotData = self.safe_dict(spot, 'data', {})
1505
2049
  askData = self.safe_dict(ask, 'data', {})
1506
2050
  bidData = self.safe_dict(bid, 'data', {})
1507
- bidAskLast = {
2051
+ bidAskLast: dict = {
1508
2052
  'bid': self.safe_number(bidData, 'amount'),
1509
2053
  'ask': self.safe_number(askData, 'amount'),
1510
2054
  'price': self.safe_number(spotData, 'amount'),
@@ -1514,11 +2058,17 @@ class coinbase(Exchange, ImplicitAPI):
1514
2058
  def fetch_ticker_v3(self, symbol: str, params={}):
1515
2059
  self.load_markets()
1516
2060
  market = self.market(symbol)
1517
- request = {
2061
+ request: dict = {
1518
2062
  'product_id': market['id'],
1519
2063
  'limit': 1,
1520
2064
  }
1521
- response = self.v3PrivateGetBrokerageProductsProductIdTicker(self.extend(request, params))
2065
+ usePrivate = False
2066
+ usePrivate, params = self.handle_option_and_params(params, 'fetchTicker', 'usePrivate', False)
2067
+ response = None
2068
+ if usePrivate:
2069
+ response = self.v3PrivateGetBrokerageProductsProductIdTicker(self.extend(request, params))
2070
+ else:
2071
+ response = self.v3PublicGetBrokerageMarketProductsProductIdTicker(self.extend(request, params))
1522
2072
  #
1523
2073
  # {
1524
2074
  # "trades": [
@@ -1543,7 +2093,7 @@ class coinbase(Exchange, ImplicitAPI):
1543
2093
  ticker['ask'] = self.safe_number(response, 'best_ask')
1544
2094
  return ticker
1545
2095
 
1546
- def parse_ticker(self, ticker, market: Market = None) -> Ticker:
2096
+ def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
1547
2097
  #
1548
2098
  # fetchTickerV2
1549
2099
  #
@@ -1665,7 +2215,7 @@ class coinbase(Exchange, ImplicitAPI):
1665
2215
  balances = self.safe_list_2(response, 'data', 'accounts', [])
1666
2216
  accounts = self.safe_list(params, 'type', self.options['accounts'])
1667
2217
  v3Accounts = self.safe_list(params, 'type', self.options['v3Accounts'])
1668
- result = {'info': response}
2218
+ result: dict = {'info': response}
1669
2219
  for b in range(0, len(balances)):
1670
2220
  balance = balances[b]
1671
2221
  type = self.safe_string(balance, 'type')
@@ -1710,25 +2260,32 @@ class coinbase(Exchange, ImplicitAPI):
1710
2260
  def fetch_balance(self, params={}) -> Balances:
1711
2261
  """
1712
2262
  query for balance and get the amount of funds available for trading or funds locked in orders
1713
- :see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getaccounts
1714
- :see: https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-accounts#list-accounts
2263
+
2264
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_getaccounts
2265
+ https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-accounts#list-accounts
2266
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_getfcmbalancesummary
2267
+
1715
2268
  :param dict [params]: extra parameters specific to the exchange API endpoint
1716
2269
  :param boolean [params.v3]: default False, set True to use v3 api endpoint
1717
- :param dict [params.type]: "spot"(default) or "swap"
2270
+ :param str [params.type]: "spot"(default) or "swap" or "future"
2271
+ :param int [params.limit]: default 250, maximum number of accounts to return
1718
2272
  :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
1719
2273
  """
1720
2274
  self.load_markets()
1721
- request = {}
2275
+ request: dict = {}
1722
2276
  response = None
1723
2277
  isV3 = self.safe_bool(params, 'v3', False)
1724
- type = self.safe_string(params, 'type')
1725
- params = self.omit(params, ['v3', 'type'])
2278
+ params = self.omit(params, ['v3'])
2279
+ marketType = None
2280
+ marketType, params = self.handle_market_type_and_params('fetchBalance', None, params)
1726
2281
  method = self.safe_string(self.options, 'fetchBalance', 'v3PrivateGetBrokerageAccounts')
1727
- if (isV3) or (method == 'v3PrivateGetBrokerageAccounts'):
2282
+ if marketType == 'future':
2283
+ response = self.v3PrivateGetBrokerageCfmBalanceSummary(self.extend(request, params))
2284
+ elif (isV3) or (method == 'v3PrivateGetBrokerageAccounts'):
1728
2285
  request['limit'] = 250
1729
2286
  response = self.v3PrivateGetBrokerageAccounts(self.extend(request, params))
1730
2287
  else:
1731
- request['limit'] = 100
2288
+ request['limit'] = 250
1732
2289
  response = self.v2PrivateGetAccounts(self.extend(request, params))
1733
2290
  #
1734
2291
  # v2PrivateGetAccounts
@@ -1801,19 +2358,21 @@ class coinbase(Exchange, ImplicitAPI):
1801
2358
  # "size": 9
1802
2359
  # }
1803
2360
  #
1804
- params['type'] = type
2361
+ params['type'] = marketType
1805
2362
  return self.parse_custom_balance(response, params)
1806
2363
 
1807
- def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
2364
+ def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[LedgerEntry]:
1808
2365
  """
1809
- fetch the history of changes, actions done by the user or operations that altered balance of the user
1810
- :see: https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-transactions#list-transactions
1811
- :param str code: unified currency code, default is None
2366
+ Fetch the history of changes, i.e. actions done by the user or operations that altered the balance. Will return staking rewards, and crypto deposits or withdrawals.
2367
+
2368
+ https://docs.cdp.coinbase.com/coinbase-app/docs/api-transactions#list-transactions
2369
+
2370
+ :param str [code]: unified currency code, default is None
1812
2371
  :param int [since]: timestamp in ms of the earliest ledger entry, default is None
1813
- :param int [limit]: max number of ledger entrys to return, default is None
2372
+ :param int [limit]: max number of ledger entries to return, default is None
1814
2373
  :param dict [params]: extra parameters specific to the exchange API endpoint
1815
- :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1816
- :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger-structure>`
2374
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
2375
+ :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger>`
1817
2376
  """
1818
2377
  self.load_markets()
1819
2378
  paginate = False
@@ -1827,27 +2386,29 @@ class coinbase(Exchange, ImplicitAPI):
1827
2386
  request, params = self.prepare_account_request_with_currency_code(code, limit, params)
1828
2387
  # for pagination use parameter 'starting_after'
1829
2388
  # the value for the next page can be obtained from the result of the previous call in the 'pagination' field
1830
- # eg: instance.last_json_response.pagination.next_starting_after
2389
+ # eg: instance.last_http_response -> pagination.next_starting_after
1831
2390
  response = self.v2PrivateGetAccountsAccountIdTransactions(self.extend(request, params))
1832
2391
  ledger = self.parse_ledger(response['data'], currency, since, limit)
1833
2392
  length = len(ledger)
2393
+ if length == 0:
2394
+ return ledger
1834
2395
  lastIndex = length - 1
1835
2396
  last = self.safe_dict(ledger, lastIndex)
1836
2397
  pagination = self.safe_dict(response, 'pagination', {})
1837
2398
  cursor = self.safe_string(pagination, 'next_starting_after')
1838
2399
  if (cursor is not None) and (cursor != ''):
1839
- last['next_starting_after'] = cursor
2400
+ last['info']['next_starting_after'] = cursor
1840
2401
  ledger[lastIndex] = last
1841
2402
  return ledger
1842
2403
 
1843
2404
  def parse_ledger_entry_status(self, status):
1844
- types = {
2405
+ types: dict = {
1845
2406
  'completed': 'ok',
1846
2407
  }
1847
2408
  return self.safe_string(types, status, status)
1848
2409
 
1849
2410
  def parse_ledger_entry_type(self, type):
1850
- types = {
2411
+ types: dict = {
1851
2412
  'buy': 'trade',
1852
2413
  'sell': 'trade',
1853
2414
  'fiat_deposit': 'transaction',
@@ -1860,7 +2421,7 @@ class coinbase(Exchange, ImplicitAPI):
1860
2421
  }
1861
2422
  return self.safe_string(types, type, type)
1862
2423
 
1863
- def parse_ledger_entry(self, item, currency: Currency = None):
2424
+ def parse_ledger_entry(self, item: dict, currency: Currency = None) -> LedgerEntry:
1864
2425
  #
1865
2426
  # crypto deposit transaction
1866
2427
  #
@@ -2114,6 +2675,7 @@ class coinbase(Exchange, ImplicitAPI):
2114
2675
  direction = 'in'
2115
2676
  currencyId = self.safe_string(amountInfo, 'currency')
2116
2677
  code = self.safe_currency_code(currencyId, currency)
2678
+ currency = self.safe_currency(currencyId, currency)
2117
2679
  #
2118
2680
  # the address and txid do not belong to the unified ledger structure
2119
2681
  #
@@ -2146,7 +2708,7 @@ class coinbase(Exchange, ImplicitAPI):
2146
2708
  numParts = len(parts)
2147
2709
  if numParts > 3:
2148
2710
  accountId = parts[3]
2149
- return {
2711
+ return self.safe_ledger_entry({
2150
2712
  'info': item,
2151
2713
  'id': id,
2152
2714
  'timestamp': timestamp,
@@ -2162,11 +2724,11 @@ class coinbase(Exchange, ImplicitAPI):
2162
2724
  'after': None,
2163
2725
  'status': status,
2164
2726
  'fee': fee,
2165
- }
2727
+ }, currency)
2166
2728
 
2167
- def find_account_id(self, code):
2729
+ def find_account_id(self, code, params={}):
2168
2730
  self.load_markets()
2169
- self.load_accounts()
2731
+ self.load_accounts(False, params)
2170
2732
  for i in range(0, len(self.accounts)):
2171
2733
  account = self.accounts[i]
2172
2734
  if account['code'] == code:
@@ -2177,7 +2739,7 @@ class coinbase(Exchange, ImplicitAPI):
2177
2739
  accountId = self.safe_string_2(params, 'account_id', 'accountId')
2178
2740
  if accountId is None:
2179
2741
  raise ArgumentsRequired(self.id + ' prepareAccountRequest() method requires an account_id(or accountId) parameter')
2180
- request = {
2742
+ request: dict = {
2181
2743
  'account_id': accountId,
2182
2744
  }
2183
2745
  if limit is not None:
@@ -2190,10 +2752,10 @@ class coinbase(Exchange, ImplicitAPI):
2190
2752
  if accountId is None:
2191
2753
  if code is None:
2192
2754
  raise ArgumentsRequired(self.id + ' prepareAccountRequestWithCurrencyCode() method requires an account_id(or accountId) parameter OR a currency code argument')
2193
- accountId = self.find_account_id(code)
2755
+ accountId = self.find_account_id(code, params)
2194
2756
  if accountId is None:
2195
2757
  raise ExchangeError(self.id + ' prepareAccountRequestWithCurrencyCode() could not find account id for ' + code)
2196
- request = {
2758
+ request: dict = {
2197
2759
  'account_id': accountId,
2198
2760
  }
2199
2761
  if limit is not None:
@@ -2203,7 +2765,9 @@ class coinbase(Exchange, ImplicitAPI):
2203
2765
  def create_market_buy_order_with_cost(self, symbol: str, cost: float, params={}):
2204
2766
  """
2205
2767
  create a market buy order by providing the symbol and cost
2206
- :see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_postorder
2768
+
2769
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_postorder
2770
+
2207
2771
  :param str symbol: unified symbol of the market to create an order in
2208
2772
  :param float cost: how much you want to trade in units of the quote currency
2209
2773
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -2219,7 +2783,9 @@ class coinbase(Exchange, ImplicitAPI):
2219
2783
  def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
2220
2784
  """
2221
2785
  create a trade order
2222
- :see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_postorder
2786
+
2787
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_postorder
2788
+
2223
2789
  :param str symbol: unified symbol of the market to create an order in
2224
2790
  :param str type: 'market' or 'limit'
2225
2791
  :param str side: 'buy' or 'sell'
@@ -2231,24 +2797,30 @@ class coinbase(Exchange, ImplicitAPI):
2231
2797
  :param float [params.stopLossPrice]: price to trigger stop-loss orders
2232
2798
  :param float [params.takeProfitPrice]: price to trigger take-profit orders
2233
2799
  :param bool [params.postOnly]: True or False
2234
- :param str [params.timeInForce]: 'GTC', 'IOC', 'GTD' or 'PO'
2800
+ :param str [params.timeInForce]: 'GTC', 'IOC', 'GTD' or 'PO', 'FOK'
2235
2801
  :param str [params.stop_direction]: 'UNKNOWN_STOP_DIRECTION', 'STOP_DIRECTION_STOP_UP', 'STOP_DIRECTION_STOP_DOWN' the direction the stopPrice is triggered from
2236
2802
  :param str [params.end_time]: '2023-05-25T17:01:05.092Z' for 'GTD' orders
2237
2803
  :param float [params.cost]: *spot market buy only* the quote quantity that can be used alternative for the amount
2238
2804
  :param boolean [params.preview]: default to False, wether to use the test/preview endpoint or not
2805
+ :param float [params.leverage]: default to 1, the leverage to use for the order
2806
+ :param str [params.marginMode]: 'cross' or 'isolated'
2807
+ :param str [params.retail_portfolio_id]: portfolio uid
2808
+ :param boolean [params.is_max]: Used in conjunction with tradable_balance to indicate the user wants to use their entire tradable balance
2809
+ :param str [params.tradable_balance]: amount of tradable balance
2239
2810
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2240
2811
  """
2241
2812
  self.load_markets()
2242
2813
  market = self.market(symbol)
2243
- request = {
2244
- 'client_order_id': self.uuid(),
2814
+ id = self.safe_string(self.options, 'brokerId', 'ccxt')
2815
+ request: dict = {
2816
+ 'client_order_id': id + '-' + self.uuid(),
2245
2817
  'product_id': market['id'],
2246
2818
  'side': side.upper(),
2247
2819
  }
2248
- stopPrice = self.safe_number_n(params, ['stopPrice', 'stop_price', 'triggerPrice'])
2820
+ triggerPrice = self.safe_number_n(params, ['stopPrice', 'stop_price', 'triggerPrice'])
2249
2821
  stopLossPrice = self.safe_number(params, 'stopLossPrice')
2250
2822
  takeProfitPrice = self.safe_number(params, 'takeProfitPrice')
2251
- isStop = stopPrice is not None
2823
+ isStop = triggerPrice is not None
2252
2824
  isStopLoss = stopLossPrice is not None
2253
2825
  isTakeProfit = takeProfitPrice is not None
2254
2826
  timeInForce = self.safe_string(params, 'timeInForce')
@@ -2266,7 +2838,7 @@ class coinbase(Exchange, ImplicitAPI):
2266
2838
  'stop_limit_stop_limit_gtd': {
2267
2839
  'base_size': self.amount_to_precision(symbol, amount),
2268
2840
  'limit_price': self.price_to_precision(symbol, price),
2269
- 'stop_price': self.price_to_precision(symbol, stopPrice),
2841
+ 'stop_price': self.price_to_precision(symbol, triggerPrice),
2270
2842
  'stop_direction': stopDirection,
2271
2843
  'end_time': endTime,
2272
2844
  },
@@ -2276,25 +2848,25 @@ class coinbase(Exchange, ImplicitAPI):
2276
2848
  'stop_limit_stop_limit_gtc': {
2277
2849
  'base_size': self.amount_to_precision(symbol, amount),
2278
2850
  'limit_price': self.price_to_precision(symbol, price),
2279
- 'stop_price': self.price_to_precision(symbol, stopPrice),
2851
+ 'stop_price': self.price_to_precision(symbol, triggerPrice),
2280
2852
  'stop_direction': stopDirection,
2281
2853
  },
2282
2854
  }
2283
2855
  elif isStopLoss or isTakeProfit:
2284
- triggerPrice = None
2856
+ tpslPrice = None
2285
2857
  if isStopLoss:
2286
2858
  if stopDirection is None:
2287
2859
  stopDirection = 'STOP_DIRECTION_STOP_UP' if (side == 'buy') else 'STOP_DIRECTION_STOP_DOWN'
2288
- triggerPrice = self.price_to_precision(symbol, stopLossPrice)
2860
+ tpslPrice = self.price_to_precision(symbol, stopLossPrice)
2289
2861
  else:
2290
2862
  if stopDirection is None:
2291
2863
  stopDirection = 'STOP_DIRECTION_STOP_DOWN' if (side == 'buy') else 'STOP_DIRECTION_STOP_UP'
2292
- triggerPrice = self.price_to_precision(symbol, takeProfitPrice)
2864
+ tpslPrice = self.price_to_precision(symbol, takeProfitPrice)
2293
2865
  request['order_configuration'] = {
2294
2866
  'stop_limit_stop_limit_gtc': {
2295
2867
  'base_size': self.amount_to_precision(symbol, amount),
2296
2868
  'limit_price': self.price_to_precision(symbol, price),
2297
- 'stop_price': triggerPrice,
2869
+ 'stop_price': tpslPrice,
2298
2870
  'stop_direction': stopDirection,
2299
2871
  },
2300
2872
  }
@@ -2317,6 +2889,13 @@ class coinbase(Exchange, ImplicitAPI):
2317
2889
  'limit_price': self.price_to_precision(symbol, price),
2318
2890
  },
2319
2891
  }
2892
+ elif timeInForce == 'FOK':
2893
+ request['order_configuration'] = {
2894
+ 'limit_limit_fok': {
2895
+ 'base_size': self.amount_to_precision(symbol, amount),
2896
+ 'limit_price': self.price_to_precision(symbol, price),
2897
+ },
2898
+ }
2320
2899
  else:
2321
2900
  request['order_configuration'] = {
2322
2901
  'limit_limit_gtc': {
@@ -2328,7 +2907,7 @@ class coinbase(Exchange, ImplicitAPI):
2328
2907
  else:
2329
2908
  if isStop or isStopLoss or isTakeProfit:
2330
2909
  raise NotSupported(self.id + ' createOrder() only stop limit orders are supported')
2331
- if side == 'buy':
2910
+ if market['spot'] and (side == 'buy'):
2332
2911
  total = None
2333
2912
  createMarketBuyOrderRequiresPrice = True
2334
2913
  createMarketBuyOrderRequiresPrice, params = self.handle_option_and_params(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', True)
@@ -2357,7 +2936,13 @@ class coinbase(Exchange, ImplicitAPI):
2357
2936
  'base_size': self.amount_to_precision(symbol, amount),
2358
2937
  },
2359
2938
  }
2360
- params = self.omit(params, ['timeInForce', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'stop_price', 'stopDirection', 'stop_direction', 'clientOrderId', 'postOnly', 'post_only', 'end_time'])
2939
+ marginMode = self.safe_string(params, 'marginMode')
2940
+ if marginMode is not None:
2941
+ if marginMode == 'isolated':
2942
+ request['margin_type'] = 'ISOLATED'
2943
+ elif marginMode == 'cross':
2944
+ request['margin_type'] = 'CROSS'
2945
+ params = self.omit(params, ['timeInForce', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'stop_price', 'stopDirection', 'stop_direction', 'clientOrderId', 'postOnly', 'post_only', 'end_time', 'marginMode'])
2361
2946
  preview = self.safe_bool_2(params, 'preview', 'test', False)
2362
2947
  response = None
2363
2948
  if preview:
@@ -2415,7 +3000,7 @@ class coinbase(Exchange, ImplicitAPI):
2415
3000
  data = self.safe_dict(response, 'success_response', {})
2416
3001
  return self.parse_order(data, market)
2417
3002
 
2418
- def parse_order(self, order, market: Market = None) -> Order:
3003
+ def parse_order(self, order: dict, market: Market = None) -> Order:
2419
3004
  #
2420
3005
  # createOrder
2421
3006
  #
@@ -2481,7 +3066,7 @@ class coinbase(Exchange, ImplicitAPI):
2481
3066
  marketId = self.safe_string(order, 'product_id')
2482
3067
  symbol = self.safe_symbol(marketId, market, '-')
2483
3068
  if symbol is not None:
2484
- market = self.market(symbol)
3069
+ market = self.safe_market(symbol, market)
2485
3070
  orderConfiguration = self.safe_dict(order, 'order_configuration', {})
2486
3071
  limitGTC = self.safe_dict(orderConfiguration, 'limit_limit_gtc')
2487
3072
  limitGTD = self.safe_dict(orderConfiguration, 'limit_limit_gtd')
@@ -2532,7 +3117,6 @@ class coinbase(Exchange, ImplicitAPI):
2532
3117
  'postOnly': postOnly,
2533
3118
  'side': self.safe_string_lower(order, 'side'),
2534
3119
  'price': price,
2535
- 'stopPrice': triggerPrice,
2536
3120
  'triggerPrice': triggerPrice,
2537
3121
  'amount': amount,
2538
3122
  'filled': self.safe_string(order, 'filled_size'),
@@ -2547,8 +3131,8 @@ class coinbase(Exchange, ImplicitAPI):
2547
3131
  'trades': None,
2548
3132
  }, market)
2549
3133
 
2550
- def parse_order_status(self, status):
2551
- statuses = {
3134
+ def parse_order_status(self, status: Str):
3135
+ statuses: dict = {
2552
3136
  'OPEN': 'open',
2553
3137
  'FILLED': 'closed',
2554
3138
  'CANCELLED': 'canceled',
@@ -2558,10 +3142,10 @@ class coinbase(Exchange, ImplicitAPI):
2558
3142
  }
2559
3143
  return self.safe_string(statuses, status, status)
2560
3144
 
2561
- def parse_order_type(self, type):
3145
+ def parse_order_type(self, type: Str):
2562
3146
  if type == 'UNKNOWN_ORDER_TYPE':
2563
3147
  return None
2564
- types = {
3148
+ types: dict = {
2565
3149
  'MARKET': 'market',
2566
3150
  'LIMIT': 'limit',
2567
3151
  'STOP': 'limit',
@@ -2569,8 +3153,8 @@ class coinbase(Exchange, ImplicitAPI):
2569
3153
  }
2570
3154
  return self.safe_string(types, type, type)
2571
3155
 
2572
- def parse_time_in_force(self, timeInForce):
2573
- timeInForces = {
3156
+ def parse_time_in_force(self, timeInForce: Str):
3157
+ timeInForces: dict = {
2574
3158
  'GOOD_UNTIL_CANCELLED': 'GTC',
2575
3159
  'GOOD_UNTIL_DATE_TIME': 'GTD',
2576
3160
  'IMMEDIATE_OR_CANCEL': 'IOC',
@@ -2582,7 +3166,9 @@ class coinbase(Exchange, ImplicitAPI):
2582
3166
  def cancel_order(self, id: str, symbol: Str = None, params={}):
2583
3167
  """
2584
3168
  cancels an open order
2585
- :see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_cancelorders
3169
+
3170
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_cancelorders
3171
+
2586
3172
  :param str id: order id
2587
3173
  :param str symbol: not used by coinbase cancelOrder()
2588
3174
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -2595,7 +3181,9 @@ class coinbase(Exchange, ImplicitAPI):
2595
3181
  def cancel_orders(self, ids, symbol: Str = None, params={}):
2596
3182
  """
2597
3183
  cancel multiple orders
2598
- :see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_cancelorders
3184
+
3185
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_cancelorders
3186
+
2599
3187
  :param str[] ids: order ids
2600
3188
  :param str symbol: not used by coinbase cancelOrders()
2601
3189
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -2605,7 +3193,7 @@ class coinbase(Exchange, ImplicitAPI):
2605
3193
  market = None
2606
3194
  if symbol is not None:
2607
3195
  market = self.market(symbol)
2608
- request = {
3196
+ request: dict = {
2609
3197
  'order_ids': ids,
2610
3198
  }
2611
3199
  response = self.v3PrivatePostBrokerageOrdersBatchCancel(self.extend(request, params))
@@ -2630,20 +3218,22 @@ class coinbase(Exchange, ImplicitAPI):
2630
3218
  def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
2631
3219
  """
2632
3220
  edit a trade order
2633
- :see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_editorder
3221
+
3222
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_editorder
3223
+
2634
3224
  :param str id: cancel order id
2635
3225
  :param str symbol: unified symbol of the market to create an order in
2636
3226
  :param str type: 'market' or 'limit'
2637
3227
  :param str side: 'buy' or 'sell'
2638
3228
  :param float amount: how much of currency you want to trade in units of base currency
2639
- :param float [price]: the price at which the order is to be fullfilled, in units of the base currency, ignored in market orders
3229
+ :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
2640
3230
  :param dict [params]: extra parameters specific to the exchange API endpoint
2641
3231
  :param boolean [params.preview]: default to False, wether to use the test/preview endpoint or not
2642
3232
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2643
3233
  """
2644
3234
  self.load_markets()
2645
3235
  market = self.market(symbol)
2646
- request = {
3236
+ request: dict = {
2647
3237
  'order_id': id,
2648
3238
  }
2649
3239
  if amount is not None:
@@ -2671,7 +3261,9 @@ class coinbase(Exchange, ImplicitAPI):
2671
3261
  def fetch_order(self, id: str, symbol: Str = None, params={}):
2672
3262
  """
2673
3263
  fetches information on an order made by the user
2674
- :see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_gethistoricalorder
3264
+
3265
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_gethistoricalorder
3266
+
2675
3267
  :param str id: the order id
2676
3268
  :param str symbol: unified market symbol that the order was made in
2677
3269
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -2681,7 +3273,7 @@ class coinbase(Exchange, ImplicitAPI):
2681
3273
  market = None
2682
3274
  if symbol is not None:
2683
3275
  market = self.market(symbol)
2684
- request = {
3276
+ request: dict = {
2685
3277
  'order_id': id,
2686
3278
  }
2687
3279
  response = self.v3PrivateGetBrokerageOrdersHistoricalOrderId(self.extend(request, params))
@@ -2730,7 +3322,9 @@ class coinbase(Exchange, ImplicitAPI):
2730
3322
  def fetch_orders(self, symbol: Str = None, since: Int = None, limit: Int = 100, params={}) -> List[Order]:
2731
3323
  """
2732
3324
  fetches information on multiple orders made by the user
2733
- :see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_gethistoricalorders
3325
+
3326
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_gethistoricalorders
3327
+
2734
3328
  :param str symbol: unified market symbol that the orders were made in
2735
3329
  :param int [since]: the earliest time in ms to fetch orders
2736
3330
  :param int [limit]: the maximum number of order structures to retrieve
@@ -2747,16 +3341,16 @@ class coinbase(Exchange, ImplicitAPI):
2747
3341
  market = None
2748
3342
  if symbol is not None:
2749
3343
  market = self.market(symbol)
2750
- request = {}
3344
+ request: dict = {}
2751
3345
  if market is not None:
2752
3346
  request['product_id'] = market['id']
2753
3347
  if limit is not None:
2754
3348
  request['limit'] = limit
2755
3349
  if since is not None:
2756
3350
  request['start_date'] = self.iso8601(since)
2757
- until = self.safe_integer_n(params, ['until', 'till'])
3351
+ until = self.safe_integer_n(params, ['until'])
2758
3352
  if until is not None:
2759
- params = self.omit(params, ['until', 'till'])
3353
+ params = self.omit(params, ['until'])
2760
3354
  request['end_date'] = self.iso8601(until)
2761
3355
  response = self.v3PrivateGetBrokerageOrdersHistoricalBatch(self.extend(request, params))
2762
3356
  #
@@ -2814,7 +3408,7 @@ class coinbase(Exchange, ImplicitAPI):
2814
3408
  market = None
2815
3409
  if symbol is not None:
2816
3410
  market = self.market(symbol)
2817
- request = {
3411
+ request: dict = {
2818
3412
  'order_status': status,
2819
3413
  }
2820
3414
  if market is not None:
@@ -2824,9 +3418,9 @@ class coinbase(Exchange, ImplicitAPI):
2824
3418
  request['limit'] = limit
2825
3419
  if since is not None:
2826
3420
  request['start_date'] = self.iso8601(since)
2827
- until = self.safe_integer_n(params, ['until', 'till'])
3421
+ until = self.safe_integer_n(params, ['until'])
2828
3422
  if until is not None:
2829
- params = self.omit(params, ['until', 'till'])
3423
+ params = self.omit(params, ['until'])
2830
3424
  request['end_date'] = self.iso8601(until)
2831
3425
  response = self.v3PrivateGetBrokerageOrdersHistoricalBatch(self.extend(request, params))
2832
3426
  #
@@ -2882,7 +3476,9 @@ class coinbase(Exchange, ImplicitAPI):
2882
3476
  def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2883
3477
  """
2884
3478
  fetches information on all currently open orders
2885
- :see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_gethistoricalorders
3479
+
3480
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_gethistoricalorders
3481
+
2886
3482
  :param str symbol: unified market symbol of the orders
2887
3483
  :param int [since]: timestamp in ms of the earliest order, default is None
2888
3484
  :param int [limit]: the maximum number of open order structures to retrieve
@@ -2901,7 +3497,9 @@ class coinbase(Exchange, ImplicitAPI):
2901
3497
  def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2902
3498
  """
2903
3499
  fetches information on multiple closed orders made by the user
2904
- :see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_gethistoricalorders
3500
+
3501
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_gethistoricalorders
3502
+
2905
3503
  :param str symbol: unified market symbol of the orders
2906
3504
  :param int [since]: timestamp in ms of the earliest order, default is None
2907
3505
  :param int [limit]: the maximum number of closed order structures to retrieve
@@ -2920,7 +3518,9 @@ class coinbase(Exchange, ImplicitAPI):
2920
3518
  def fetch_canceled_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
2921
3519
  """
2922
3520
  fetches information on multiple canceled orders made by the user
2923
- :see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_gethistoricalorders
3521
+
3522
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_gethistoricalorders
3523
+
2924
3524
  :param str symbol: unified market symbol of the orders
2925
3525
  :param int [since]: timestamp in ms of the earliest order, default is None
2926
3526
  :param int [limit]: the maximum number of canceled order structures to retrieve
@@ -2932,7 +3532,9 @@ class coinbase(Exchange, ImplicitAPI):
2932
3532
  def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
2933
3533
  """
2934
3534
  fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
2935
- :see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getcandles
3535
+
3536
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_getpubliccandles
3537
+
2936
3538
  :param str symbol: unified symbol of the market to fetch OHLCV data for
2937
3539
  :param str timeframe: the length of time each candle represents
2938
3540
  :param int [since]: timestamp in ms of the earliest candle to fetch
@@ -2940,6 +3542,7 @@ class coinbase(Exchange, ImplicitAPI):
2940
3542
  :param dict [params]: extra parameters specific to the exchange API endpoint
2941
3543
  :param int [params.until]: the latest time in ms to fetch trades for
2942
3544
  :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
3545
+ :param boolean [params.usePrivate]: default False, when True will use the private endpoint to fetch the candles
2943
3546
  :returns int[][]: A list of candles ordered, open, high, low, close, volume
2944
3547
  """
2945
3548
  self.load_markets()
@@ -2950,12 +3553,12 @@ class coinbase(Exchange, ImplicitAPI):
2950
3553
  if paginate:
2951
3554
  return self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, maxLimit - 1)
2952
3555
  market = self.market(symbol)
2953
- request = {
3556
+ request: dict = {
2954
3557
  'product_id': market['id'],
2955
3558
  'granularity': self.safe_string(self.timeframes, timeframe, timeframe),
2956
3559
  }
2957
- until = self.safe_integer_n(params, ['until', 'till', 'end'])
2958
- params = self.omit(params, ['until', 'till'])
3560
+ until = self.safe_integer_n(params, ['until', 'end'])
3561
+ params = self.omit(params, ['until'])
2959
3562
  duration = self.parse_timeframe(timeframe)
2960
3563
  requestedDuration = limit * duration
2961
3564
  sinceString = None
@@ -2965,12 +3568,18 @@ class coinbase(Exchange, ImplicitAPI):
2965
3568
  now = str(self.seconds())
2966
3569
  sinceString = Precise.string_sub(now, str(requestedDuration))
2967
3570
  request['start'] = sinceString
2968
- endString = self.number_to_string(until)
2969
- if until is None:
3571
+ if until is not None:
3572
+ request['end'] = self.number_to_string(self.parse_to_int(until / 1000))
3573
+ else:
2970
3574
  # 300 candles max
2971
- endString = Precise.string_add(sinceString, str(requestedDuration))
2972
- request['end'] = endString
2973
- response = self.v3PrivateGetBrokerageProductsProductIdCandles(self.extend(request, params))
3575
+ request['end'] = Precise.string_add(sinceString, str(requestedDuration))
3576
+ response = None
3577
+ usePrivate = False
3578
+ usePrivate, params = self.handle_option_and_params(params, 'fetchOHLCV', 'usePrivate', False)
3579
+ if usePrivate:
3580
+ response = self.v3PrivateGetBrokerageProductsProductIdCandles(self.extend(request, params))
3581
+ else:
3582
+ response = self.v3PublicGetBrokerageMarketProductsProductIdCandles(self.extend(request, params))
2974
3583
  #
2975
3584
  # {
2976
3585
  # "candles": [
@@ -3013,16 +3622,19 @@ class coinbase(Exchange, ImplicitAPI):
3013
3622
  def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
3014
3623
  """
3015
3624
  get the list of most recent trades for a particular symbol
3016
- :see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getmarkettrades
3625
+
3626
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_getpublicmarkettrades
3627
+
3017
3628
  :param str symbol: unified market symbol of the trades
3018
3629
  :param int [since]: not used by coinbase fetchTrades
3019
3630
  :param int [limit]: the maximum number of trade structures to fetch
3020
3631
  :param dict [params]: extra parameters specific to the exchange API endpoint
3632
+ :param boolean [params.usePrivate]: default False, when True will use the private endpoint to fetch the trades
3021
3633
  :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
3022
3634
  """
3023
3635
  self.load_markets()
3024
3636
  market = self.market(symbol)
3025
- request = {
3637
+ request: dict = {
3026
3638
  'product_id': market['id'],
3027
3639
  }
3028
3640
  if since is not None:
@@ -3035,7 +3647,13 @@ class coinbase(Exchange, ImplicitAPI):
3035
3647
  request['end'] = self.number_to_string(self.parse_to_int(until / 1000))
3036
3648
  elif since is not None:
3037
3649
  raise ArgumentsRequired(self.id + ' fetchTrades() requires a `until` parameter when you use `since` argument')
3038
- response = self.v3PrivateGetBrokerageProductsProductIdTicker(self.extend(request, params))
3650
+ response = None
3651
+ usePrivate = False
3652
+ usePrivate, params = self.handle_option_and_params(params, 'fetchTrades', 'usePrivate', False)
3653
+ if usePrivate:
3654
+ response = self.v3PrivateGetBrokerageProductsProductIdTicker(self.extend(request, params))
3655
+ else:
3656
+ response = self.v3PublicGetBrokerageMarketProductsProductIdTicker(self.extend(request, params))
3039
3657
  #
3040
3658
  # {
3041
3659
  # "trades": [
@@ -3058,7 +3676,9 @@ class coinbase(Exchange, ImplicitAPI):
3058
3676
  def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
3059
3677
  """
3060
3678
  fetch all trades made by the user
3061
- :see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getfills
3679
+
3680
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_getfills
3681
+
3062
3682
  :param str symbol: unified market symbol of the trades
3063
3683
  :param int [since]: timestamp in ms of the earliest order, default is None
3064
3684
  :param int [limit]: the maximum number of trade structures to fetch
@@ -3071,20 +3691,20 @@ class coinbase(Exchange, ImplicitAPI):
3071
3691
  paginate = False
3072
3692
  paginate, params = self.handle_option_and_params(params, 'fetchMyTrades', 'paginate')
3073
3693
  if paginate:
3074
- return self.fetch_paginated_call_cursor('fetchMyTrades', symbol, since, limit, params, 'cursor', 'cursor', None, 100)
3694
+ return self.fetch_paginated_call_cursor('fetchMyTrades', symbol, since, limit, params, 'cursor', 'cursor', None, 250)
3075
3695
  market = None
3076
3696
  if symbol is not None:
3077
3697
  market = self.market(symbol)
3078
- request = {}
3698
+ request: dict = {}
3079
3699
  if market is not None:
3080
3700
  request['product_id'] = market['id']
3081
3701
  if limit is not None:
3082
3702
  request['limit'] = limit
3083
3703
  if since is not None:
3084
3704
  request['start_sequence_timestamp'] = self.iso8601(since)
3085
- until = self.safe_integer_n(params, ['until', 'till'])
3705
+ until = self.safe_integer_n(params, ['until'])
3086
3706
  if until is not None:
3087
- params = self.omit(params, ['until', 'till'])
3707
+ params = self.omit(params, ['until'])
3088
3708
  request['end_sequence_timestamp'] = self.iso8601(until)
3089
3709
  response = self.v3PrivateGetBrokerageOrdersHistoricalFills(self.extend(request, params))
3090
3710
  #
@@ -3121,20 +3741,29 @@ class coinbase(Exchange, ImplicitAPI):
3121
3741
  def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
3122
3742
  """
3123
3743
  fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
3124
- :see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getproductbook
3744
+
3745
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_getpublicproductbook
3746
+
3125
3747
  :param str symbol: unified symbol of the market to fetch the order book for
3126
3748
  :param int [limit]: the maximum amount of order book entries to return
3127
3749
  :param dict [params]: extra parameters specific to the exchange API endpoint
3750
+ :param boolean [params.usePrivate]: default False, when True will use the private endpoint to fetch the order book
3128
3751
  :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
3129
3752
  """
3130
3753
  self.load_markets()
3131
3754
  market = self.market(symbol)
3132
- request = {
3755
+ request: dict = {
3133
3756
  'product_id': market['id'],
3134
3757
  }
3135
3758
  if limit is not None:
3136
3759
  request['limit'] = limit
3137
- response = self.v3PrivateGetBrokerageProductBook(self.extend(request, params))
3760
+ response = None
3761
+ usePrivate = False
3762
+ usePrivate, params = self.handle_option_and_params(params, 'fetchOrderBook', 'usePrivate', False)
3763
+ if usePrivate:
3764
+ response = self.v3PrivateGetBrokerageProductBook(self.extend(request, params))
3765
+ else:
3766
+ response = self.v3PublicGetBrokerageMarketProductBook(self.extend(request, params))
3138
3767
  #
3139
3768
  # {
3140
3769
  # "pricebook": {
@@ -3163,14 +3792,16 @@ class coinbase(Exchange, ImplicitAPI):
3163
3792
  def fetch_bids_asks(self, symbols: Strings = None, params={}):
3164
3793
  """
3165
3794
  fetches the bid and ask price and volume for multiple markets
3166
- :see: https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getbestbidask
3795
+
3796
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_getbestbidask
3797
+
3167
3798
  :param str[] [symbols]: unified symbols of the markets to fetch the bids and asks for, all markets are returned if not assigned
3168
3799
  :param dict [params]: extra parameters specific to the exchange API endpoint
3169
3800
  :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
3170
3801
  """
3171
3802
  self.load_markets()
3172
3803
  symbols = self.market_symbols(symbols)
3173
- request = {}
3804
+ request: dict = {}
3174
3805
  if symbols is not None:
3175
3806
  request['product_ids'] = self.market_ids(symbols)
3176
3807
  response = self.v3PrivateGetBrokerageBestBidAsk(self.extend(request, params))
@@ -3199,10 +3830,12 @@ class coinbase(Exchange, ImplicitAPI):
3199
3830
  tickers = self.safe_list(response, 'pricebooks', [])
3200
3831
  return self.parse_tickers(tickers, symbols)
3201
3832
 
3202
- def withdraw(self, code: str, amount: float, address, tag=None, params={}):
3833
+ def withdraw(self, code: str, amount: float, address: str, tag=None, params={}) -> Transaction:
3203
3834
  """
3204
3835
  make a withdrawal
3205
- :see: https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-transactions#send-money
3836
+
3837
+ https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-transactions#send-money
3838
+
3206
3839
  :param str code: unified currency code
3207
3840
  :param float amount: the amount to withdraw
3208
3841
  :param str address: the address to withdraw to
@@ -3219,10 +3852,10 @@ class coinbase(Exchange, ImplicitAPI):
3219
3852
  if accountId is None:
3220
3853
  if code is None:
3221
3854
  raise ArgumentsRequired(self.id + ' withdraw() requires an account_id(or accountId) parameter OR a currency code argument')
3222
- accountId = self.find_account_id(code)
3855
+ accountId = self.find_account_id(code, params)
3223
3856
  if accountId is None:
3224
3857
  raise ExchangeError(self.id + ' withdraw() could not find account id for ' + code)
3225
- request = {
3858
+ request: dict = {
3226
3859
  'account_id': accountId,
3227
3860
  'type': 'send',
3228
3861
  'to': address,
@@ -3287,10 +3920,12 @@ class coinbase(Exchange, ImplicitAPI):
3287
3920
  data = self.safe_dict(response, 'data', {})
3288
3921
  return self.parse_transaction(data, currency)
3289
3922
 
3290
- def fetch_deposit_addresses_by_network(self, code: str, params={}):
3923
+ def fetch_deposit_addresses_by_network(self, code: str, params={}) -> List[DepositAddress]:
3291
3924
  """
3292
3925
  fetch the deposit address for a currency associated with self account
3293
- :see: https://docs.cloud.coinbase.com/exchange/reference/exchangerestapi_postcoinbaseaccountaddresses
3926
+
3927
+ https://docs.cloud.coinbase.com/exchange/reference/exchangerestapi_postcoinbaseaccountaddresses
3928
+
3294
3929
  :param str code: unified currency code
3295
3930
  :param dict [params]: extra parameters specific to the exchange API endpoint
3296
3931
  :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
@@ -3359,7 +3994,7 @@ class coinbase(Exchange, ImplicitAPI):
3359
3994
  addressStructures = self.parse_deposit_addresses(data, None, False)
3360
3995
  return self.index_by(addressStructures, 'network')
3361
3996
 
3362
- def parse_deposit_address(self, depositAddress, currency: Currency = None):
3997
+ def parse_deposit_address(self, depositAddress, currency: Currency = None) -> DepositAddress:
3363
3998
  #
3364
3999
  # {
3365
4000
  # id: '64ceb5f1-5fa2-5310-a4ff-9fd46271003d',
@@ -3414,15 +4049,17 @@ class coinbase(Exchange, ImplicitAPI):
3414
4049
  return {
3415
4050
  'info': depositAddress,
3416
4051
  'currency': self.safe_currency_code(marketId, currency),
4052
+ 'network': self.network_id_to_code(networkId, code),
3417
4053
  'address': address,
3418
4054
  'tag': self.safe_string(addressInfo, 'destination_tag'),
3419
- 'network': self.network_id_to_code(networkId, code),
3420
4055
  }
3421
4056
 
3422
4057
  def deposit(self, code: str, amount: float, id: str, params={}):
3423
4058
  """
3424
4059
  make a deposit
3425
- :see: https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-deposits#deposit-funds
4060
+
4061
+ https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-deposits#deposit-funds
4062
+
3426
4063
  :param str code: unified currency code
3427
4064
  :param float amount: the amount to deposit
3428
4065
  :param str id: the payment method id to be used for the deposit, can be retrieved from v2PrivateGetPaymentMethods
@@ -3436,10 +4073,10 @@ class coinbase(Exchange, ImplicitAPI):
3436
4073
  if accountId is None:
3437
4074
  if code is None:
3438
4075
  raise ArgumentsRequired(self.id + ' deposit() requires an account_id(or accountId) parameter OR a currency code argument')
3439
- accountId = self.find_account_id(code)
4076
+ accountId = self.find_account_id(code, params)
3440
4077
  if accountId is None:
3441
4078
  raise ExchangeError(self.id + ' deposit() could not find account id for ' + code)
3442
- request = {
4079
+ request: dict = {
3443
4080
  'account_id': accountId,
3444
4081
  'amount': self.number_to_string(amount),
3445
4082
  'currency': code.upper(), # need to use code in case depositing USD etc.
@@ -3488,7 +4125,9 @@ class coinbase(Exchange, ImplicitAPI):
3488
4125
  def fetch_deposit(self, id: str, code: Str = None, params={}):
3489
4126
  """
3490
4127
  fetch information on a deposit, fiat only, for crypto transactions use fetchLedger
3491
- :see: https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-deposits#show-deposit
4128
+
4129
+ https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-deposits#show-deposit
4130
+
3492
4131
  :param str id: deposit id
3493
4132
  :param str [code]: unified currency code
3494
4133
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -3501,10 +4140,10 @@ class coinbase(Exchange, ImplicitAPI):
3501
4140
  if accountId is None:
3502
4141
  if code is None:
3503
4142
  raise ArgumentsRequired(self.id + ' fetchDeposit() requires an account_id(or accountId) parameter OR a currency code argument')
3504
- accountId = self.find_account_id(code)
4143
+ accountId = self.find_account_id(code, params)
3505
4144
  if accountId is None:
3506
4145
  raise ExchangeError(self.id + ' fetchDeposit() could not find account id for ' + code)
3507
- request = {
4146
+ request: dict = {
3508
4147
  'account_id': accountId,
3509
4148
  'deposit_id': id,
3510
4149
  }
@@ -3548,6 +4187,508 @@ class coinbase(Exchange, ImplicitAPI):
3548
4187
  data = self.safe_dict(response, 'data', {})
3549
4188
  return self.parse_transaction(data)
3550
4189
 
4190
+ def fetch_deposit_method_ids(self, params={}):
4191
+ """
4192
+ fetch the deposit id for a fiat currency associated with self account
4193
+
4194
+ https://docs.cdp.coinbase.com/advanced-trade/reference/retailbrokerageapi_getpaymentmethods
4195
+
4196
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4197
+ :returns dict: an array of `deposit id structures <https://docs.ccxt.com/#/?id=deposit-id-structure>`
4198
+ """
4199
+ self.load_markets()
4200
+ response = self.v3PrivateGetBrokeragePaymentMethods(params)
4201
+ #
4202
+ # {
4203
+ # "payment_methods": [
4204
+ # {
4205
+ # "id": "21b39a5d-f7b46876fb2e",
4206
+ # "type": "COINBASE_FIAT_ACCOUNT",
4207
+ # "name": "CAD Wallet",
4208
+ # "currency": "CAD",
4209
+ # "verified": True,
4210
+ # "allow_buy": False,
4211
+ # "allow_sell": True,
4212
+ # "allow_deposit": False,
4213
+ # "allow_withdraw": False,
4214
+ # "created_at": "2023-06-29T19:58:46Z",
4215
+ # "updated_at": "2023-10-30T20:25:01Z"
4216
+ # }
4217
+ # ]
4218
+ # }
4219
+ #
4220
+ result = self.safe_list(response, 'payment_methods', [])
4221
+ return self.parse_deposit_method_ids(result)
4222
+
4223
+ def fetch_deposit_method_id(self, id: str, params={}):
4224
+ """
4225
+ fetch the deposit id for a fiat currency associated with self account
4226
+
4227
+ https://docs.cdp.coinbase.com/advanced-trade/reference/retailbrokerageapi_getpaymentmethod
4228
+
4229
+ :param str id: the deposit payment method id
4230
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4231
+ :returns dict: a `deposit id structure <https://docs.ccxt.com/#/?id=deposit-id-structure>`
4232
+ """
4233
+ self.load_markets()
4234
+ request: dict = {
4235
+ 'payment_method_id': id,
4236
+ }
4237
+ response = self.v3PrivateGetBrokeragePaymentMethodsPaymentMethodId(self.extend(request, params))
4238
+ #
4239
+ # {
4240
+ # "payment_method": {
4241
+ # "id": "21b39a5d-f7b46876fb2e",
4242
+ # "type": "COINBASE_FIAT_ACCOUNT",
4243
+ # "name": "CAD Wallet",
4244
+ # "currency": "CAD",
4245
+ # "verified": True,
4246
+ # "allow_buy": False,
4247
+ # "allow_sell": True,
4248
+ # "allow_deposit": False,
4249
+ # "allow_withdraw": False,
4250
+ # "created_at": "2023-06-29T19:58:46Z",
4251
+ # "updated_at": "2023-10-30T20:25:01Z"
4252
+ # }
4253
+ # }
4254
+ #
4255
+ result = self.safe_dict(response, 'payment_method', {})
4256
+ return self.parse_deposit_method_id(result)
4257
+
4258
+ def parse_deposit_method_ids(self, ids, params={}):
4259
+ result = []
4260
+ for i in range(0, len(ids)):
4261
+ id = self.extend(self.parse_deposit_method_id(ids[i]), params)
4262
+ result.append(id)
4263
+ return result
4264
+
4265
+ def parse_deposit_method_id(self, depositId):
4266
+ return {
4267
+ 'info': depositId,
4268
+ 'id': self.safe_string(depositId, 'id'),
4269
+ 'currency': self.safe_string(depositId, 'currency'),
4270
+ 'verified': self.safe_bool(depositId, 'verified'),
4271
+ 'tag': self.safe_string(depositId, 'name'),
4272
+ }
4273
+
4274
+ def fetch_convert_quote(self, fromCode: str, toCode: str, amount: Num = None, params={}) -> Conversion:
4275
+ """
4276
+ fetch a quote for converting from one currency to another
4277
+
4278
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_createconvertquote
4279
+
4280
+ :param str fromCode: the currency that you want to sell and convert from
4281
+ :param str toCode: the currency that you want to buy and convert into
4282
+ :param float [amount]: how much you want to trade in units of the from currency
4283
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4284
+ :param dict [params.trade_incentive_metadata]: an object to fill in user incentive data
4285
+ :param str [params.trade_incentive_metadata.user_incentive_id]: the id of the incentive
4286
+ :param str [params.trade_incentive_metadata.code_val]: the code value of the incentive
4287
+ :returns dict: a `conversion structure <https://docs.ccxt.com/#/?id=conversion-structure>`
4288
+ """
4289
+ self.load_markets()
4290
+ request: dict = {
4291
+ 'from_account': fromCode,
4292
+ 'to_account': toCode,
4293
+ 'amount': self.number_to_string(amount),
4294
+ }
4295
+ response = self.v3PrivatePostBrokerageConvertQuote(self.extend(request, params))
4296
+ data = self.safe_dict(response, 'trade', {})
4297
+ return self.parse_conversion(data)
4298
+
4299
+ def create_convert_trade(self, id: str, fromCode: str, toCode: str, amount: Num = None, params={}) -> Conversion:
4300
+ """
4301
+ convert from one currency to another
4302
+
4303
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_commitconverttrade
4304
+
4305
+ :param str id: the id of the trade that you want to make
4306
+ :param str fromCode: the currency that you want to sell and convert from
4307
+ :param str toCode: the currency that you want to buy and convert into
4308
+ :param float [amount]: how much you want to trade in units of the from currency
4309
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4310
+ :returns dict: a `conversion structure <https://docs.ccxt.com/#/?id=conversion-structure>`
4311
+ """
4312
+ self.load_markets()
4313
+ request: dict = {
4314
+ 'trade_id': id,
4315
+ 'from_account': fromCode,
4316
+ 'to_account': toCode,
4317
+ }
4318
+ response = self.v3PrivatePostBrokerageConvertTradeTradeId(self.extend(request, params))
4319
+ data = self.safe_dict(response, 'trade', {})
4320
+ return self.parse_conversion(data)
4321
+
4322
+ def fetch_convert_trade(self, id: str, code: Str = None, params={}) -> Conversion:
4323
+ """
4324
+ fetch the data for a conversion trade
4325
+
4326
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_getconverttrade
4327
+
4328
+ :param str id: the id of the trade that you want to commit
4329
+ :param str code: the unified currency code that was converted from
4330
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4331
+ :param strng params['toCode']: the unified currency code that was converted into
4332
+ :returns dict: a `conversion structure <https://docs.ccxt.com/#/?id=conversion-structure>`
4333
+ """
4334
+ self.load_markets()
4335
+ if code is None:
4336
+ raise ArgumentsRequired(self.id + ' fetchConvertTrade() requires a code argument')
4337
+ toCode = self.safe_string(params, 'toCode')
4338
+ if toCode is None:
4339
+ raise ArgumentsRequired(self.id + ' fetchConvertTrade() requires a toCode parameter')
4340
+ params = self.omit(params, 'toCode')
4341
+ request: dict = {
4342
+ 'trade_id': id,
4343
+ 'from_account': code,
4344
+ 'to_account': toCode,
4345
+ }
4346
+ response = self.v3PrivateGetBrokerageConvertTradeTradeId(self.extend(request, params))
4347
+ data = self.safe_dict(response, 'trade', {})
4348
+ return self.parse_conversion(data)
4349
+
4350
+ def parse_conversion(self, conversion: dict, fromCurrency: Currency = None, toCurrency: Currency = None) -> Conversion:
4351
+ fromCoin = self.safe_string(conversion, 'source_currency')
4352
+ fromCode = self.safe_currency_code(fromCoin, fromCurrency)
4353
+ to = self.safe_string(conversion, 'target_currency')
4354
+ toCode = self.safe_currency_code(to, toCurrency)
4355
+ fromAmountStructure = self.safe_dict(conversion, 'user_entered_amount')
4356
+ feeStructure = self.safe_dict(conversion, 'total_fee')
4357
+ feeAmountStructure = self.safe_dict(feeStructure, 'amount')
4358
+ return {
4359
+ 'info': conversion,
4360
+ 'timestamp': None,
4361
+ 'datetime': None,
4362
+ 'id': self.safe_string(conversion, 'id'),
4363
+ 'fromCurrency': fromCode,
4364
+ 'fromAmount': self.safe_number(fromAmountStructure, 'value'),
4365
+ 'toCurrency': toCode,
4366
+ 'toAmount': None,
4367
+ 'price': None,
4368
+ 'fee': self.safe_number(feeAmountStructure, 'value'),
4369
+ }
4370
+
4371
+ def close_position(self, symbol: str, side: OrderSide = None, params={}) -> Order:
4372
+ """
4373
+ *futures only* closes open positions for a market
4374
+
4375
+ https://coinbase-api.github.io/docs/#/en-us/swapV2/trade-api.html#One-Click%20Close%20All%20Positions
4376
+
4377
+ :param str symbol: Unified CCXT market symbol
4378
+ :param str [side]: not used by coinbase
4379
+ :param dict [params]: extra parameters specific to the coinbase api endpoint
4380
+ @param {str} params.clientOrderId *mandatory* the client order id of the position to close
4381
+ :param float [params.size]: the size of the position to close, optional
4382
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
4383
+ """
4384
+ self.load_markets()
4385
+ market = self.market(symbol)
4386
+ if not market['future']:
4387
+ raise NotSupported(self.id + ' closePosition() only supported for futures markets')
4388
+ clientOrderId = self.safe_string_2(params, 'client_order_id', 'clientOrderId')
4389
+ params = self.omit(params, 'clientOrderId')
4390
+ request: dict = {
4391
+ 'product_id': market['id'],
4392
+ }
4393
+ if clientOrderId is None:
4394
+ raise ArgumentsRequired(self.id + ' closePosition() requires a clientOrderId parameter')
4395
+ request['client_order_id'] = clientOrderId
4396
+ response = self.v3PrivatePostBrokerageOrdersClosePosition(self.extend(request, params))
4397
+ order = self.safe_dict(response, 'success_response', {})
4398
+ return self.parse_order(order)
4399
+
4400
+ def fetch_positions(self, symbols: Strings = None, params={}):
4401
+ """
4402
+ fetch all open positions
4403
+
4404
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_getfcmpositions
4405
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_getintxpositions
4406
+
4407
+ :param str[] [symbols]: list of unified market symbols
4408
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4409
+ :param str [params.portfolio]: the portfolio UUID to fetch positions for
4410
+ :returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
4411
+ """
4412
+ self.load_markets()
4413
+ symbols = self.market_symbols(symbols)
4414
+ market = None
4415
+ if symbols is not None:
4416
+ market = self.market(symbols[0])
4417
+ type = None
4418
+ type, params = self.handle_market_type_and_params('fetchPositions', market, params)
4419
+ response = None
4420
+ if type == 'future':
4421
+ response = self.v3PrivateGetBrokerageCfmPositions(params)
4422
+ else:
4423
+ portfolio = None
4424
+ portfolio, params = self.handle_option_and_params(params, 'fetchPositions', 'portfolio')
4425
+ if portfolio is None:
4426
+ raise ArgumentsRequired(self.id + ' fetchPositions() requires a "portfolio" value in params(eg: dbcb91e7-2bc9-515), or set.options["portfolio"]. You can get a list of portfolios with fetchPortfolios()')
4427
+ request: dict = {
4428
+ 'portfolio_uuid': portfolio,
4429
+ }
4430
+ response = self.v3PrivateGetBrokerageIntxPositionsPortfolioUuid(self.extend(request, params))
4431
+ positions = self.safe_list(response, 'positions', [])
4432
+ return self.parse_positions(positions, symbols)
4433
+
4434
+ def fetch_position(self, symbol: str, params={}):
4435
+ """
4436
+ fetch data on a single open contract trade position
4437
+
4438
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_getintxposition
4439
+ https://docs.cloud.coinbase.com/advanced-trade/reference/retailbrokerageapi_getfcmposition
4440
+
4441
+ :param str symbol: unified market symbol of the market the position is held in, default is None
4442
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4443
+ :param str [params.product_id]: *futures only* the product id of the position to fetch, required for futures markets only
4444
+ :param str [params.portfolio]: *perpetual/swaps only* the portfolio UUID to fetch the position for, required for perpetual/swaps markets only
4445
+ :returns dict: a `position structure <https://docs.ccxt.com/#/?id=position-structure>`
4446
+ """
4447
+ self.load_markets()
4448
+ market = self.market(symbol)
4449
+ response = None
4450
+ if market['future']:
4451
+ productId = self.safe_string(market, 'product_id')
4452
+ if productId is None:
4453
+ raise ArgumentsRequired(self.id + ' fetchPosition() requires a "product_id" in params')
4454
+ futureRequest: dict = {
4455
+ 'product_id': productId,
4456
+ }
4457
+ response = self.v3PrivateGetBrokerageCfmPositionsProductId(self.extend(futureRequest, params))
4458
+ else:
4459
+ portfolio = None
4460
+ portfolio, params = self.handle_option_and_params(params, 'fetchPositions', 'portfolio')
4461
+ if portfolio is None:
4462
+ raise ArgumentsRequired(self.id + ' fetchPosition() requires a "portfolio" value in params(eg: dbcb91e7-2bc9-515), or set.options["portfolio"]. You can get a list of portfolios with fetchPortfolios()')
4463
+ request: dict = {
4464
+ 'symbol': market['id'],
4465
+ 'portfolio_uuid': portfolio,
4466
+ }
4467
+ response = self.v3PrivateGetBrokerageIntxPositionsPortfolioUuidSymbol(self.extend(request, params))
4468
+ position = self.safe_dict(response, 'position', {})
4469
+ return self.parse_position(position, market)
4470
+
4471
+ def parse_position(self, position: dict, market: Market = None):
4472
+ #
4473
+ # {
4474
+ # "product_id": "1r4njf84-0-0",
4475
+ # "product_uuid": "cd34c18b-3665-4ed8-9305-3db277c49fc5",
4476
+ # "symbol": "ADA-PERP-INTX",
4477
+ # "vwap": {
4478
+ # "value": "0.6171",
4479
+ # "currency": "USDC"
4480
+ # },
4481
+ # "position_side": "POSITION_SIDE_LONG",
4482
+ # "net_size": "20",
4483
+ # "buy_order_size": "0",
4484
+ # "sell_order_size": "0",
4485
+ # "im_contribution": "0.1",
4486
+ # "unrealized_pnl": {
4487
+ # "value": "0.074",
4488
+ # "currency": "USDC"
4489
+ # },
4490
+ # "mark_price": {
4491
+ # "value": "0.6208",
4492
+ # "currency": "USDC"
4493
+ # },
4494
+ # "liquidation_price": {
4495
+ # "value": "0",
4496
+ # "currency": "USDC"
4497
+ # },
4498
+ # "leverage": "1",
4499
+ # "im_notional": {
4500
+ # "value": "12.342",
4501
+ # "currency": "USDC"
4502
+ # },
4503
+ # "mm_notional": {
4504
+ # "value": "0.814572",
4505
+ # "currency": "USDC"
4506
+ # },
4507
+ # "position_notional": {
4508
+ # "value": "12.342",
4509
+ # "currency": "USDC"
4510
+ # },
4511
+ # "margin_type": "MARGIN_TYPE_CROSS",
4512
+ # "liquidation_buffer": "19.677828",
4513
+ # "liquidation_percentage": "4689.3506",
4514
+ # "portfolio_summary": {
4515
+ # "portfolio_uuid": "018ebd63-1f6d-7c8e-ada9-0761c5a2235f",
4516
+ # "collateral": "20.4184",
4517
+ # "position_notional": "12.342",
4518
+ # "open_position_notional": "12.342",
4519
+ # "pending_fees": "0",
4520
+ # "borrow": "0",
4521
+ # "accrued_interest": "0",
4522
+ # "rolling_debt": "0",
4523
+ # "portfolio_initial_margin": "0.1",
4524
+ # "portfolio_im_notional": {
4525
+ # "value": "12.342",
4526
+ # "currency": "USDC"
4527
+ # },
4528
+ # "portfolio_maintenance_margin": "0.066",
4529
+ # "portfolio_mm_notional": {
4530
+ # "value": "0.814572",
4531
+ # "currency": "USDC"
4532
+ # },
4533
+ # "liquidation_percentage": "4689.3506",
4534
+ # "liquidation_buffer": "19.677828",
4535
+ # "margin_type": "MARGIN_TYPE_CROSS",
4536
+ # "margin_flags": "PORTFOLIO_MARGIN_FLAGS_UNSPECIFIED",
4537
+ # "liquidation_status": "PORTFOLIO_LIQUIDATION_STATUS_NOT_LIQUIDATING",
4538
+ # "unrealized_pnl": {
4539
+ # "value": "0.074",
4540
+ # "currency": "USDC"
4541
+ # },
4542
+ # "buying_power": {
4543
+ # "value": "8.1504",
4544
+ # "currency": "USDC"
4545
+ # },
4546
+ # "total_balance": {
4547
+ # "value": "20.4924",
4548
+ # "currency": "USDC"
4549
+ # },
4550
+ # "max_withdrawal": {
4551
+ # "value": "8.0764",
4552
+ # "currency": "USDC"
4553
+ # }
4554
+ # },
4555
+ # "entry_vwap": {
4556
+ # "value": "0.6091",
4557
+ # "currency": "USDC"
4558
+ # }
4559
+ # }
4560
+ #
4561
+ marketId = self.safe_string(position, 'symbol', '')
4562
+ market = self.safe_market(marketId, market)
4563
+ rawMargin = self.safe_string(position, 'margin_type')
4564
+ marginMode = None
4565
+ if rawMargin is not None:
4566
+ marginMode = 'cross' if (rawMargin == 'MARGIN_TYPE_CROSS') else 'isolated'
4567
+ notionalObject = self.safe_dict(position, 'position_notional', {})
4568
+ positionSide = self.safe_string(position, 'position_side')
4569
+ side = 'long' if (positionSide == 'POSITION_SIDE_LONG') else 'short'
4570
+ unrealizedPNLObject = self.safe_dict(position, 'unrealized_pnl', {})
4571
+ liquidationPriceObject = self.safe_dict(position, 'liquidation_price', {})
4572
+ liquidationPrice = self.safe_number(liquidationPriceObject, 'value')
4573
+ vwapObject = self.safe_dict(position, 'vwap', {})
4574
+ summaryObject = self.safe_dict(position, 'portfolio_summary', {})
4575
+ return self.safe_position({
4576
+ 'info': position,
4577
+ 'id': self.safe_string(position, 'product_id'),
4578
+ 'symbol': self.safe_symbol(marketId, market),
4579
+ 'notional': self.safe_number(notionalObject, 'value'),
4580
+ 'marginMode': marginMode,
4581
+ 'liquidationPrice': liquidationPrice,
4582
+ 'entryPrice': self.safe_number(vwapObject, 'value'),
4583
+ 'unrealizedPnl': self.safe_number(unrealizedPNLObject, 'value'),
4584
+ 'realizedPnl': None,
4585
+ 'percentage': None,
4586
+ 'contracts': self.safe_number(position, 'net_size'),
4587
+ 'contractSize': market['contractSize'],
4588
+ 'markPrice': None,
4589
+ 'lastPrice': None,
4590
+ 'side': side,
4591
+ 'hedged': None,
4592
+ 'timestamp': None,
4593
+ 'datetime': None,
4594
+ 'lastUpdateTimestamp': None,
4595
+ 'maintenanceMargin': None,
4596
+ 'maintenanceMarginPercentage': None,
4597
+ 'collateral': self.safe_number(summaryObject, 'collateral'),
4598
+ 'initialMargin': None,
4599
+ 'initialMarginPercentage': None,
4600
+ 'leverage': self.safe_number(position, 'leverage'),
4601
+ 'marginRatio': None,
4602
+ 'stopLossPrice': None,
4603
+ 'takeProfitPrice': None,
4604
+ })
4605
+
4606
+ def fetch_trading_fees(self, params={}) -> TradingFees:
4607
+ """
4608
+
4609
+ https://docs.cdp.coinbase.com/advanced-trade/reference/retailbrokerageapi_gettransactionsummary/
4610
+
4611
+ fetch the trading fees for multiple markets
4612
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4613
+ :param str [params.type]: 'spot' or 'swap'
4614
+ :returns dict: a dictionary of `fee structures <https://docs.ccxt.com/#/?id=fee-structure>` indexed by market symbols
4615
+ """
4616
+ self.load_markets()
4617
+ type = None
4618
+ type, params = self.handle_market_type_and_params('fetchTradingFees', None, params)
4619
+ isSpot = (type == 'spot')
4620
+ productType = 'SPOT' if isSpot else 'FUTURE'
4621
+ request: dict = {
4622
+ 'product_type': productType,
4623
+ }
4624
+ response = self.v3PrivateGetBrokerageTransactionSummary(self.extend(request, params))
4625
+ #
4626
+ # {
4627
+ # total_volume: '0',
4628
+ # total_fees: '0',
4629
+ # fee_tier: {
4630
+ # pricing_tier: 'Advanced 1',
4631
+ # usd_from: '0',
4632
+ # usd_to: '1000',
4633
+ # taker_fee_rate: '0.008',
4634
+ # maker_fee_rate: '0.006',
4635
+ # aop_from: '',
4636
+ # aop_to: ''
4637
+ # },
4638
+ # margin_rate: null,
4639
+ # goods_and_services_tax: null,
4640
+ # advanced_trade_only_volume: '0',
4641
+ # advanced_trade_only_fees: '0',
4642
+ # coinbase_pro_volume: '0',
4643
+ # coinbase_pro_fees: '0',
4644
+ # total_balance: '',
4645
+ # has_promo_fee: False
4646
+ # }
4647
+ #
4648
+ data = self.safe_dict(response, 'fee_tier', {})
4649
+ taker_fee = self.safe_number(data, 'taker_fee_rate')
4650
+ marker_fee = self.safe_number(data, 'maker_fee_rate')
4651
+ result: dict = {}
4652
+ for i in range(0, len(self.symbols)):
4653
+ symbol = self.symbols[i]
4654
+ market = self.market(symbol)
4655
+ if (isSpot and market['spot']) or (not isSpot and not market['spot']):
4656
+ result[symbol] = {
4657
+ 'info': response,
4658
+ 'symbol': symbol,
4659
+ 'maker': taker_fee,
4660
+ 'taker': marker_fee,
4661
+ 'percentage': True,
4662
+ }
4663
+ return result
4664
+
4665
+ def create_auth_token(self, seconds: Int, method: Str = None, url: Str = None):
4666
+ # it may not work for v2
4667
+ uri = None
4668
+ if url is not None:
4669
+ uri = method + ' ' + url.replace('https://', '')
4670
+ quesPos = uri.find('?')
4671
+ # Due to we use mb_strpos, quesPos could be False in php. In that case, the quesPos >= 0 is True
4672
+ # Also it's not possible that the question mark is first character, only check > 0 here.
4673
+ if quesPos > 0:
4674
+ uri = uri[0:quesPos]
4675
+ nonce = self.random_bytes(16)
4676
+ request: dict = {
4677
+ 'aud': ['retail_rest_api_proxy'],
4678
+ 'iss': 'coinbase-cloud',
4679
+ 'nbf': seconds,
4680
+ 'exp': seconds + 120,
4681
+ 'sub': self.apiKey,
4682
+ 'iat': seconds,
4683
+ }
4684
+ if uri is not None:
4685
+ request['uri'] = uri
4686
+ token = self.jwt(request, self.encode(self.secret), 'sha256', False, {'kid': self.apiKey, 'nonce': nonce, 'alg': 'ES256'})
4687
+ return token
4688
+
4689
+ def nonce(self):
4690
+ return self.milliseconds() - self.options['timeDifference']
4691
+
3551
4692
  def sign(self, path, api=[], method='GET', params={}, headers=None, body=None):
3552
4693
  version = api[0]
3553
4694
  signed = api[1] == 'private'
@@ -3562,25 +4703,14 @@ class coinbase(Exchange, ImplicitAPI):
3562
4703
  url = self.urls['api']['rest'] + fullPath
3563
4704
  if signed:
3564
4705
  authorization = self.safe_string(self.headers, 'Authorization')
4706
+ authorizationString = None
3565
4707
  if authorization is not None:
3566
- headers = {
3567
- 'Authorization': authorization,
3568
- 'Content-Type': 'application/json',
3569
- }
3570
- if method != 'GET':
3571
- if query:
3572
- body = self.json(query)
4708
+ authorizationString = authorization
3573
4709
  elif self.token and not self.check_required_credentials(False):
3574
- headers = {
3575
- 'Authorization': 'Bearer ' + self.token,
3576
- 'Content-Type': 'application/json',
3577
- }
3578
- if method != 'GET':
3579
- if query:
3580
- body = self.json(query)
4710
+ authorizationString = 'Bearer ' + self.token
3581
4711
  else:
3582
4712
  self.check_required_credentials()
3583
- timestampString = str(self.seconds())
4713
+ seconds = self.seconds()
3584
4714
  payload = ''
3585
4715
  if method != 'GET':
3586
4716
  if query:
@@ -3591,20 +4721,57 @@ class coinbase(Exchange, ImplicitAPI):
3591
4721
  if query:
3592
4722
  payload += '?' + self.urlencode(query)
3593
4723
  # v3: 'GET' doesn't need payload in the signature. inside url is enough
3594
- # https://docs.cloud.coinbase.com/advanced-trade-api/docs/auth#example-request
4724
+ # https://docs.cloud.coinbase.com/advanced-trade/docs/auth#example-request
3595
4725
  # v2: 'GET' require payload in the signature
3596
4726
  # https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-key-authentication
3597
- auth = timestampString + method + savedPath + payload
3598
- signature = self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha256)
4727
+ isCloudAPiKey = (self.apiKey.find('organizations/') >= 0) or (self.secret.startswith('-----BEGIN'))
4728
+ if isCloudAPiKey:
4729
+ if self.apiKey.startswith('-----BEGIN'):
4730
+ raise ArgumentsRequired(self.id + ' apiKey should contain the name(eg: organizations/3b910e93....) and not the public key')
4731
+ # # it may not work for v2
4732
+ # uri = method + ' ' + url.replace('https://', '')
4733
+ # quesPos = uri.find('?')
4734
+ # # Due to we use mb_strpos, quesPos could be False in php. In that case, the quesPos >= 0 is True
4735
+ # # Also it's not possible that the question mark is first character, only check > 0 here.
4736
+ # if quesPos > 0:
4737
+ # uri = uri[0:quesPos]
4738
+ # }
4739
+ # nonce = self.random_bytes(16)
4740
+ # request: Dict = {
4741
+ # 'aud': ['retail_rest_api_proxy'],
4742
+ # 'iss': 'coinbase-cloud',
4743
+ # 'nbf': seconds,
4744
+ # 'exp': seconds + 120,
4745
+ # 'sub': self.apiKey,
4746
+ # 'uri': uri,
4747
+ # 'iat': seconds,
4748
+ # }
4749
+ token = self.create_auth_token(seconds, method, url)
4750
+ # token = self.jwt(request, self.encode(self.secret), 'sha256', False, {'kid': self.apiKey, 'nonce': nonce, 'alg': 'ES256'})
4751
+ authorizationString = 'Bearer ' + token
4752
+ else:
4753
+ nonce = self.nonce()
4754
+ timestamp = self.parse_to_int(nonce / 1000)
4755
+ timestampString = str(timestamp)
4756
+ auth = timestampString + method + savedPath + payload
4757
+ signature = self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha256)
4758
+ headers = {
4759
+ 'CB-ACCESS-KEY': self.apiKey,
4760
+ 'CB-ACCESS-SIGN': signature,
4761
+ 'CB-ACCESS-TIMESTAMP': timestampString,
4762
+ 'Content-Type': 'application/json',
4763
+ }
4764
+ if authorizationString is not None:
3599
4765
  headers = {
3600
- 'CB-ACCESS-KEY': self.apiKey,
3601
- 'CB-ACCESS-SIGN': signature,
3602
- 'CB-ACCESS-TIMESTAMP': timestampString,
4766
+ 'Authorization': authorizationString,
3603
4767
  'Content-Type': 'application/json',
3604
4768
  }
4769
+ if method != 'GET':
4770
+ if query:
4771
+ body = self.json(query)
3605
4772
  return {'url': url, 'method': method, 'body': body, 'headers': headers}
3606
4773
 
3607
- def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
4774
+ def handle_errors(self, code: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
3608
4775
  if response is None:
3609
4776
  return None # fallback to default error handler
3610
4777
  feedback = self.id + ' ' + body