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