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.
- ccxt/__init__.py +36 -14
- ccxt/abstract/alpaca.py +4 -0
- ccxt/abstract/bigone.py +1 -1
- ccxt/abstract/binance.py +112 -48
- ccxt/abstract/binancecoinm.py +112 -48
- ccxt/abstract/binanceus.py +147 -83
- ccxt/abstract/binanceusdm.py +112 -48
- ccxt/abstract/bingx.py +133 -78
- ccxt/abstract/bitbank.py +5 -0
- ccxt/abstract/bitfinex.py +136 -65
- ccxt/abstract/bitfinex1.py +69 -0
- ccxt/abstract/bitflyer.py +1 -0
- ccxt/abstract/bitget.py +8 -1
- ccxt/abstract/bitmart.py +13 -1
- ccxt/abstract/bitopro.py +1 -0
- ccxt/abstract/bitpanda.py +0 -12
- ccxt/abstract/bitrue.py +3 -3
- ccxt/abstract/bitstamp.py +26 -3
- ccxt/abstract/blofin.py +24 -0
- ccxt/abstract/btcbox.py +1 -0
- ccxt/abstract/bybit.py +29 -14
- ccxt/abstract/cex.py +28 -29
- ccxt/abstract/coinbase.py +6 -0
- ccxt/abstract/coinbaseadvanced.py +94 -0
- ccxt/abstract/{coinbasepro.py → coinbaseexchange.py} +1 -0
- ccxt/abstract/coinbaseinternational.py +1 -1
- ccxt/abstract/coincatch.py +94 -0
- ccxt/abstract/coinex.py +233 -123
- ccxt/abstract/coinmetro.py +1 -0
- ccxt/abstract/cryptocom.py +14 -0
- ccxt/abstract/defx.py +69 -0
- ccxt/abstract/deribit.py +1 -0
- ccxt/abstract/digifinex.py +1 -0
- ccxt/abstract/ellipx.py +25 -0
- ccxt/abstract/gate.py +20 -0
- ccxt/abstract/gateio.py +20 -0
- ccxt/abstract/gemini.py +1 -0
- ccxt/abstract/hashkey.py +67 -0
- ccxt/abstract/hyperliquid.py +1 -1
- ccxt/abstract/independentreserve.py +6 -0
- ccxt/abstract/kraken.py +4 -3
- ccxt/abstract/krakenfutures.py +4 -0
- ccxt/abstract/kucoin.py +24 -0
- ccxt/abstract/kucoinfutures.py +34 -0
- ccxt/abstract/luno.py +2 -0
- ccxt/abstract/mexc.py +4 -0
- ccxt/abstract/myokx.py +340 -0
- ccxt/abstract/oceanex.py +5 -0
- ccxt/abstract/okx.py +30 -0
- ccxt/abstract/onetrading.py +0 -12
- ccxt/abstract/oxfun.py +34 -0
- ccxt/abstract/paradex.py +40 -0
- ccxt/abstract/phemex.py +1 -0
- ccxt/abstract/upbit.py +4 -0
- ccxt/abstract/vertex.py +19 -0
- ccxt/abstract/whitebit.py +31 -1
- ccxt/abstract/woo.py +6 -2
- ccxt/abstract/woofipro.py +119 -0
- ccxt/abstract/xt.py +153 -0
- ccxt/abstract/zonda.py +6 -0
- ccxt/ace.py +164 -60
- ccxt/alpaca.py +727 -63
- ccxt/ascendex.py +395 -249
- ccxt/async_support/__init__.py +36 -14
- ccxt/async_support/ace.py +164 -60
- ccxt/async_support/alpaca.py +727 -63
- ccxt/async_support/ascendex.py +396 -249
- ccxt/async_support/base/exchange.py +531 -155
- ccxt/async_support/base/ws/aiohttp_client.py +28 -5
- ccxt/async_support/base/ws/cache.py +3 -2
- ccxt/async_support/base/ws/client.py +26 -5
- ccxt/async_support/base/ws/fast_client.py +4 -3
- ccxt/async_support/base/ws/functions.py +1 -1
- ccxt/async_support/base/ws/future.py +40 -31
- ccxt/async_support/base/ws/order_book_side.py +3 -0
- ccxt/async_support/bequant.py +1 -1
- ccxt/async_support/bigone.py +329 -202
- ccxt/async_support/binance.py +3030 -1087
- ccxt/async_support/binancecoinm.py +2 -1
- ccxt/async_support/binanceus.py +12 -1
- ccxt/async_support/binanceusdm.py +3 -1
- ccxt/async_support/bingx.py +3104 -880
- ccxt/async_support/bit2c.py +119 -38
- ccxt/async_support/bitbank.py +215 -76
- ccxt/async_support/bitbns.py +124 -53
- ccxt/async_support/bitfinex.py +3236 -1078
- ccxt/async_support/bitfinex1.py +1711 -0
- ccxt/async_support/bitflyer.py +238 -49
- ccxt/async_support/bitget.py +1513 -563
- ccxt/async_support/bithumb.py +199 -65
- ccxt/async_support/bitmart.py +1320 -435
- ccxt/async_support/bitmex.py +308 -111
- ccxt/async_support/bitopro.py +256 -96
- ccxt/async_support/bitrue.py +365 -233
- ccxt/async_support/bitso.py +201 -89
- ccxt/async_support/bitstamp.py +438 -269
- ccxt/async_support/bitteam.py +179 -73
- ccxt/async_support/bitvavo.py +180 -70
- ccxt/async_support/bl3p.py +92 -25
- ccxt/async_support/blockchaincom.py +193 -79
- ccxt/async_support/blofin.py +392 -148
- ccxt/async_support/btcalpha.py +161 -55
- ccxt/async_support/btcbox.py +250 -34
- ccxt/async_support/btcmarkets.py +232 -85
- ccxt/async_support/btcturk.py +159 -60
- ccxt/async_support/bybit.py +2231 -1193
- ccxt/async_support/cex.py +1409 -1329
- ccxt/async_support/coinbase.py +1454 -287
- ccxt/async_support/coinbaseadvanced.py +17 -0
- ccxt/async_support/{coinbasepro.py → coinbaseexchange.py} +233 -99
- ccxt/async_support/coinbaseinternational.py +428 -88
- ccxt/async_support/coincatch.py +5152 -0
- ccxt/async_support/coincheck.py +121 -38
- ccxt/async_support/coinex.py +4020 -3339
- ccxt/async_support/coinlist.py +273 -116
- ccxt/async_support/coinmate.py +204 -97
- ccxt/async_support/coinmetro.py +203 -110
- ccxt/async_support/coinone.py +142 -68
- ccxt/async_support/coinsph.py +206 -89
- ccxt/async_support/coinspot.py +137 -62
- ccxt/async_support/cryptocom.py +515 -185
- ccxt/async_support/currencycom.py +203 -85
- ccxt/async_support/defx.py +2066 -0
- ccxt/async_support/delta.py +404 -109
- ccxt/async_support/deribit.py +557 -323
- ccxt/async_support/digifinex.py +340 -223
- ccxt/async_support/ellipx.py +1826 -0
- ccxt/async_support/exmo.py +259 -128
- ccxt/async_support/gate.py +1472 -463
- ccxt/async_support/gemini.py +206 -84
- ccxt/async_support/hashkey.py +4164 -0
- ccxt/async_support/hitbtc.py +334 -178
- ccxt/async_support/hollaex.py +134 -83
- ccxt/async_support/htx.py +1095 -563
- ccxt/async_support/huobijp.py +105 -56
- ccxt/async_support/hyperliquid.py +1633 -268
- ccxt/async_support/idex.py +148 -95
- ccxt/async_support/independentreserve.py +236 -31
- ccxt/async_support/indodax.py +165 -62
- ccxt/async_support/kraken.py +871 -354
- ccxt/async_support/krakenfutures.py +324 -100
- ccxt/async_support/kucoin.py +917 -357
- ccxt/async_support/kucoinfutures.py +1004 -149
- ccxt/async_support/kuna.py +138 -106
- ccxt/async_support/latoken.py +135 -79
- ccxt/async_support/lbank.py +290 -113
- ccxt/async_support/luno.py +112 -62
- ccxt/async_support/lykke.py +104 -55
- ccxt/async_support/mercado.py +36 -29
- ccxt/async_support/mexc.py +995 -429
- ccxt/async_support/myokx.py +43 -0
- ccxt/async_support/ndax.py +163 -82
- ccxt/async_support/novadax.py +121 -75
- ccxt/async_support/oceanex.py +175 -59
- ccxt/async_support/okcoin.py +222 -163
- ccxt/async_support/okx.py +1776 -454
- ccxt/async_support/onetrading.py +132 -414
- ccxt/async_support/oxfun.py +2832 -0
- ccxt/async_support/p2b.py +79 -51
- ccxt/async_support/paradex.py +2017 -0
- ccxt/async_support/paymium.py +56 -32
- ccxt/async_support/phemex.py +572 -196
- ccxt/async_support/poloniex.py +218 -95
- ccxt/async_support/poloniexfutures.py +260 -92
- ccxt/async_support/probit.py +143 -110
- ccxt/async_support/timex.py +123 -70
- ccxt/async_support/tokocrypto.py +129 -93
- ccxt/async_support/tradeogre.py +39 -25
- ccxt/async_support/upbit.py +322 -113
- ccxt/async_support/vertex.py +2983 -0
- ccxt/async_support/wavesexchange.py +227 -173
- ccxt/async_support/wazirx.py +145 -65
- ccxt/async_support/whitebit.py +533 -138
- ccxt/async_support/woo.py +1137 -296
- ccxt/async_support/woofipro.py +2716 -0
- ccxt/async_support/xt.py +4628 -0
- ccxt/async_support/yobit.py +160 -92
- ccxt/async_support/zaif.py +80 -33
- ccxt/async_support/zonda.py +140 -69
- ccxt/base/errors.py +51 -20
- ccxt/base/exchange.py +1722 -480
- ccxt/base/precise.py +10 -0
- ccxt/base/types.py +223 -4
- ccxt/bequant.py +1 -1
- ccxt/bigone.py +329 -202
- ccxt/binance.py +3030 -1087
- ccxt/binancecoinm.py +2 -1
- ccxt/binanceus.py +12 -1
- ccxt/binanceusdm.py +3 -1
- ccxt/bingx.py +3104 -880
- ccxt/bit2c.py +119 -38
- ccxt/bitbank.py +215 -76
- ccxt/bitbns.py +124 -53
- ccxt/bitfinex.py +3235 -1078
- ccxt/bitfinex1.py +1710 -0
- ccxt/bitflyer.py +238 -49
- ccxt/bitget.py +1513 -563
- ccxt/bithumb.py +198 -65
- ccxt/bitmart.py +1320 -435
- ccxt/bitmex.py +308 -111
- ccxt/bitopro.py +256 -96
- ccxt/bitrue.py +365 -233
- ccxt/bitso.py +201 -89
- ccxt/bitstamp.py +438 -269
- ccxt/bitteam.py +179 -73
- ccxt/bitvavo.py +180 -70
- ccxt/bl3p.py +92 -25
- ccxt/blockchaincom.py +193 -79
- ccxt/blofin.py +392 -148
- ccxt/btcalpha.py +161 -55
- ccxt/btcbox.py +250 -34
- ccxt/btcmarkets.py +232 -85
- ccxt/btcturk.py +159 -60
- ccxt/bybit.py +2231 -1193
- ccxt/cex.py +1408 -1329
- ccxt/coinbase.py +1454 -287
- ccxt/coinbaseadvanced.py +17 -0
- ccxt/{coinbasepro.py → coinbaseexchange.py} +233 -99
- ccxt/coinbaseinternational.py +428 -88
- ccxt/coincatch.py +5152 -0
- ccxt/coincheck.py +121 -38
- ccxt/coinex.py +4020 -3339
- ccxt/coinlist.py +273 -116
- ccxt/coinmate.py +204 -97
- ccxt/coinmetro.py +203 -110
- ccxt/coinone.py +142 -68
- ccxt/coinsph.py +206 -89
- ccxt/coinspot.py +137 -62
- ccxt/cryptocom.py +515 -185
- ccxt/currencycom.py +203 -85
- ccxt/defx.py +2065 -0
- ccxt/delta.py +404 -109
- ccxt/deribit.py +557 -323
- ccxt/digifinex.py +340 -223
- ccxt/ellipx.py +1826 -0
- ccxt/exmo.py +259 -128
- ccxt/gate.py +1472 -463
- ccxt/gemini.py +206 -84
- ccxt/hashkey.py +4164 -0
- ccxt/hitbtc.py +334 -178
- ccxt/hollaex.py +134 -83
- ccxt/htx.py +1095 -563
- ccxt/huobijp.py +105 -56
- ccxt/hyperliquid.py +1632 -268
- ccxt/idex.py +148 -95
- ccxt/independentreserve.py +235 -31
- ccxt/indodax.py +165 -62
- ccxt/kraken.py +871 -354
- ccxt/krakenfutures.py +324 -100
- ccxt/kucoin.py +917 -357
- ccxt/kucoinfutures.py +1004 -149
- ccxt/kuna.py +138 -106
- ccxt/latoken.py +135 -79
- ccxt/lbank.py +290 -113
- ccxt/luno.py +112 -62
- ccxt/lykke.py +104 -55
- ccxt/mercado.py +36 -29
- ccxt/mexc.py +994 -429
- ccxt/myokx.py +43 -0
- ccxt/ndax.py +163 -82
- ccxt/novadax.py +121 -75
- ccxt/oceanex.py +175 -59
- ccxt/okcoin.py +222 -163
- ccxt/okx.py +1776 -454
- ccxt/onetrading.py +132 -414
- ccxt/oxfun.py +2831 -0
- ccxt/p2b.py +79 -51
- ccxt/paradex.py +2017 -0
- ccxt/paymium.py +56 -32
- ccxt/phemex.py +572 -196
- ccxt/poloniex.py +218 -95
- ccxt/poloniexfutures.py +260 -92
- ccxt/pro/__init__.py +29 -5
- ccxt/pro/alpaca.py +32 -17
- ccxt/pro/ascendex.py +62 -14
- ccxt/pro/bequant.py +4 -0
- ccxt/pro/binance.py +1596 -329
- ccxt/pro/binancecoinm.py +1 -0
- ccxt/pro/binanceus.py +2 -9
- ccxt/pro/binanceusdm.py +2 -0
- ccxt/pro/bingx.py +527 -134
- ccxt/pro/bitcoincom.py +4 -1
- ccxt/pro/bitfinex.py +731 -266
- ccxt/pro/bitfinex1.py +635 -0
- ccxt/pro/bitget.py +726 -357
- ccxt/pro/bithumb.py +380 -0
- ccxt/pro/bitmart.py +138 -39
- ccxt/pro/bitmex.py +199 -40
- ccxt/pro/bitopro.py +25 -13
- ccxt/pro/bitrue.py +31 -32
- ccxt/pro/bitstamp.py +7 -6
- ccxt/pro/bitvavo.py +203 -81
- ccxt/pro/blockchaincom.py +30 -17
- ccxt/pro/blofin.py +692 -0
- ccxt/pro/bybit.py +791 -82
- ccxt/pro/cex.py +99 -51
- ccxt/pro/coinbase.py +220 -30
- ccxt/{async_support/hitbtc3.py → pro/coinbaseadvanced.py} +5 -5
- ccxt/pro/{coinbasepro.py → coinbaseexchange.py} +19 -19
- ccxt/pro/coinbaseinternational.py +193 -30
- ccxt/pro/coincatch.py +1464 -0
- ccxt/pro/coincheck.py +11 -6
- ccxt/pro/coinex.py +965 -665
- ccxt/pro/coinone.py +17 -10
- ccxt/pro/cryptocom.py +446 -66
- ccxt/pro/currencycom.py +11 -10
- ccxt/pro/defx.py +832 -0
- ccxt/pro/deribit.py +167 -31
- ccxt/pro/exmo.py +252 -20
- ccxt/pro/gate.py +729 -64
- ccxt/pro/gemini.py +44 -26
- ccxt/pro/hashkey.py +802 -0
- ccxt/pro/hitbtc.py +208 -103
- ccxt/pro/hollaex.py +25 -9
- ccxt/pro/htx.py +83 -39
- ccxt/pro/huobijp.py +17 -16
- ccxt/pro/hyperliquid.py +502 -31
- ccxt/pro/idex.py +28 -13
- ccxt/pro/independentreserve.py +21 -16
- ccxt/pro/kraken.py +298 -51
- ccxt/pro/krakenfutures.py +166 -75
- ccxt/pro/kucoin.py +395 -77
- ccxt/pro/kucoinfutures.py +400 -99
- ccxt/pro/lbank.py +52 -31
- ccxt/pro/luno.py +12 -10
- ccxt/pro/mexc.py +400 -50
- ccxt/pro/myokx.py +28 -0
- ccxt/pro/ndax.py +25 -12
- ccxt/pro/okcoin.py +28 -9
- ccxt/pro/okx.py +935 -124
- ccxt/pro/onetrading.py +41 -24
- ccxt/pro/oxfun.py +1054 -0
- ccxt/pro/p2b.py +100 -24
- ccxt/pro/paradex.py +352 -0
- ccxt/pro/phemex.py +92 -33
- ccxt/pro/poloniex.py +128 -49
- ccxt/pro/poloniexfutures.py +53 -32
- ccxt/pro/probit.py +92 -85
- ccxt/pro/upbit.py +401 -8
- ccxt/pro/vertex.py +943 -0
- ccxt/pro/wazirx.py +46 -28
- ccxt/pro/whitebit.py +65 -12
- ccxt/pro/woo.py +437 -65
- ccxt/pro/woofipro.py +1271 -0
- ccxt/pro/xt.py +1067 -0
- ccxt/probit.py +143 -110
- ccxt/static_dependencies/__init__.py +1 -1
- ccxt/static_dependencies/lark/__init__.py +38 -0
- ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
- ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
- ccxt/static_dependencies/lark/ast_utils.py +59 -0
- ccxt/static_dependencies/lark/common.py +86 -0
- ccxt/static_dependencies/lark/exceptions.py +292 -0
- ccxt/static_dependencies/lark/grammar.py +130 -0
- ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
- ccxt/static_dependencies/lark/indenter.py +143 -0
- ccxt/static_dependencies/lark/lark.py +658 -0
- ccxt/static_dependencies/lark/lexer.py +678 -0
- ccxt/static_dependencies/lark/load_grammar.py +1428 -0
- ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
- ccxt/static_dependencies/lark/parser_frontends.py +257 -0
- ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
- ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
- ccxt/static_dependencies/lark/parsers/earley.py +314 -0
- ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
- ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
- ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
- ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
- ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
- ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
- ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
- ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
- ccxt/static_dependencies/lark/py.typed +0 -0
- ccxt/static_dependencies/lark/reconstruct.py +107 -0
- ccxt/static_dependencies/lark/tools/__init__.py +70 -0
- ccxt/static_dependencies/lark/tools/nearley.py +202 -0
- ccxt/static_dependencies/lark/tools/serialize.py +32 -0
- ccxt/static_dependencies/lark/tools/standalone.py +196 -0
- ccxt/static_dependencies/lark/tree.py +267 -0
- ccxt/static_dependencies/lark/tree_matcher.py +186 -0
- ccxt/static_dependencies/lark/tree_templates.py +180 -0
- ccxt/static_dependencies/lark/utils.py +343 -0
- ccxt/static_dependencies/lark/visitors.py +596 -0
- ccxt/static_dependencies/marshmallow/__init__.py +81 -0
- ccxt/static_dependencies/marshmallow/base.py +65 -0
- ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
- ccxt/static_dependencies/marshmallow/decorators.py +231 -0
- ccxt/static_dependencies/marshmallow/error_store.py +60 -0
- ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
- ccxt/static_dependencies/marshmallow/fields.py +2114 -0
- ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
- ccxt/static_dependencies/marshmallow/py.typed +0 -0
- ccxt/static_dependencies/marshmallow/schema.py +1228 -0
- ccxt/static_dependencies/marshmallow/types.py +12 -0
- ccxt/static_dependencies/marshmallow/utils.py +378 -0
- ccxt/static_dependencies/marshmallow/validate.py +678 -0
- ccxt/static_dependencies/marshmallow/warnings.py +2 -0
- ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
- ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
- ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
- ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
- ccxt/static_dependencies/marshmallow_dataclass/py.typed +0 -0
- ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
- ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
- ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
- ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
- ccxt/static_dependencies/marshmallow_oneofschema/py.typed +0 -0
- ccxt/static_dependencies/starknet/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
- ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
- ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
- ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
- ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
- ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
- ccxt/static_dependencies/starknet/common.py +15 -0
- ccxt/static_dependencies/starknet/constants.py +39 -0
- ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
- ccxt/static_dependencies/starknet/hash/address.py +79 -0
- ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
- ccxt/static_dependencies/starknet/hash/selector.py +16 -0
- ccxt/static_dependencies/starknet/hash/storage.py +12 -0
- ccxt/static_dependencies/starknet/hash/utils.py +78 -0
- ccxt/static_dependencies/starknet/models/__init__.py +0 -0
- ccxt/static_dependencies/starknet/models/typed_data.py +45 -0
- ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
- ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
- ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
- ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
- ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
- ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
- ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
- ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
- ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
- ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
- ccxt/static_dependencies/starknet/utils/schema.py +13 -0
- ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
- ccxt/static_dependencies/starkware/__init__.py +0 -0
- ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
- ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +50 -0
- ccxt/static_dependencies/starkware/crypto/math_utils.py +78 -0
- ccxt/static_dependencies/starkware/crypto/signature.py +2344 -0
- ccxt/static_dependencies/starkware/crypto/utils.py +63 -0
- ccxt/static_dependencies/sympy/__init__.py +0 -0
- ccxt/static_dependencies/sympy/core/__init__.py +0 -0
- ccxt/static_dependencies/sympy/core/intfunc.py +35 -0
- ccxt/static_dependencies/sympy/external/__init__.py +0 -0
- ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
- ccxt/static_dependencies/sympy/external/importtools.py +187 -0
- ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
- ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
- ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
- ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
- ccxt/test/{test_async.py → tests_async.py} +456 -391
- ccxt/test/tests_helpers.py +285 -0
- ccxt/test/tests_init.py +39 -0
- ccxt/test/{test_sync.py → tests_sync.py} +456 -393
- ccxt/timex.py +123 -70
- ccxt/tokocrypto.py +129 -93
- ccxt/tradeogre.py +39 -25
- ccxt/upbit.py +322 -113
- ccxt/vertex.py +2983 -0
- ccxt/wavesexchange.py +227 -173
- ccxt/wazirx.py +145 -65
- ccxt/whitebit.py +533 -138
- ccxt/woo.py +1137 -296
- ccxt/woofipro.py +2716 -0
- ccxt/xt.py +4627 -0
- ccxt/yobit.py +159 -92
- ccxt/zaif.py +80 -33
- ccxt/zonda.py +140 -69
- ccxt-4.4.48.dist-info/LICENSE.txt +21 -0
- ccxt-4.4.48.dist-info/METADATA +646 -0
- ccxt-4.4.48.dist-info/RECORD +669 -0
- {ccxt-4.2.77.dist-info → ccxt-4.4.48.dist-info}/WHEEL +1 -1
- ccxt/abstract/bitbay.py +0 -47
- ccxt/abstract/bitfinex2.py +0 -139
- ccxt/abstract/hitbtc3.py +0 -115
- ccxt/async_support/bitbay.py +0 -17
- ccxt/async_support/bitfinex2.py +0 -3496
- ccxt/async_support/flowbtc.py +0 -34
- ccxt/bitbay.py +0 -17
- ccxt/bitfinex2.py +0 -3496
- ccxt/flowbtc.py +0 -34
- ccxt/hitbtc3.py +0 -16
- ccxt/pro/bitfinex2.py +0 -1081
- ccxt/test/base/__init__.py +0 -28
- ccxt/test/base/test_account.py +0 -26
- ccxt/test/base/test_balance.py +0 -56
- ccxt/test/base/test_borrow_interest.py +0 -35
- ccxt/test/base/test_borrow_rate.py +0 -32
- ccxt/test/base/test_calculate_fee.py +0 -51
- ccxt/test/base/test_crypto.py +0 -127
- ccxt/test/base/test_currency.py +0 -76
- ccxt/test/base/test_datetime.py +0 -103
- ccxt/test/base/test_decimal_to_precision.py +0 -392
- ccxt/test/base/test_deep_extend.py +0 -68
- ccxt/test/base/test_deposit_withdrawal.py +0 -50
- ccxt/test/base/test_exchange_datetime_functions.py +0 -76
- ccxt/test/base/test_funding_rate_history.py +0 -29
- ccxt/test/base/test_last_price.py +0 -32
- ccxt/test/base/test_ledger_entry.py +0 -45
- ccxt/test/base/test_ledger_item.py +0 -48
- ccxt/test/base/test_leverage_tier.py +0 -33
- ccxt/test/base/test_margin_mode.py +0 -24
- ccxt/test/base/test_margin_modification.py +0 -35
- ccxt/test/base/test_market.py +0 -190
- ccxt/test/base/test_number.py +0 -411
- ccxt/test/base/test_ohlcv.py +0 -32
- ccxt/test/base/test_open_interest.py +0 -32
- ccxt/test/base/test_order.py +0 -64
- ccxt/test/base/test_order_book.py +0 -63
- ccxt/test/base/test_position.py +0 -60
- ccxt/test/base/test_shared_methods.py +0 -345
- ccxt/test/base/test_status.py +0 -24
- ccxt/test/base/test_throttle.py +0 -126
- ccxt/test/base/test_ticker.py +0 -86
- ccxt/test/base/test_trade.py +0 -47
- ccxt/test/base/test_trading_fee.py +0 -26
- ccxt/test/base/test_transaction.py +0 -39
- ccxt-4.2.77.dist-info/METADATA +0 -626
- ccxt-4.2.77.dist-info/RECORD +0 -534
- {ccxt-4.2.77.dist-info → ccxt-4.4.48.dist-info}/top_level.txt +0 -0
ccxt/async_support/coinbase.py
CHANGED
@@ -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
|
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':
|
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':
|
119
|
+
'fetchPosition': True,
|
111
120
|
'fetchPositionMode': False,
|
112
|
-
'fetchPositions':
|
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':
|
120
|
-
'fetchTradingFees':
|
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
|
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.
|
269
|
-
'maker': self.parse_number('0.
|
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
|
-
|
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
|
-
|
408
|
-
|
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,
|
490
|
-
request = {
|
491
|
-
'limit':
|
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
|
-
|
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
|
-
|
805
|
+
@ignore
|
676
806
|
fetch sells
|
677
|
-
|
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
|
-
|
825
|
+
@ignore
|
694
826
|
fetch buys
|
695
|
-
|
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
|
-
|
719
|
-
|
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
|
-
|
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
|
-
|
732
|
-
|
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
|
-
|
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
|
743
|
-
|
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
|
-
|
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
|
-
|
884
|
-
|
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':
|
892
|
-
'address':
|
893
|
-
'addressTo':
|
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':
|
899
|
-
'amount': self.
|
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
|
-
|
1037
|
-
|
1038
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
#
|
1155
|
-
#
|
1156
|
-
#
|
1157
|
-
#
|
1158
|
-
#
|
1159
|
-
#
|
1160
|
-
#
|
1161
|
-
#
|
1162
|
-
#
|
1163
|
-
#
|
1164
|
-
#
|
1165
|
-
#
|
1166
|
-
#
|
1167
|
-
#
|
1168
|
-
#
|
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
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
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
|
-
'
|
1215
|
-
'
|
1216
|
-
|
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
|
-
'
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
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
|
-
|
1286
|
-
|
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
|
-
|
1374
|
-
|
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
|
-
|
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
|
-
|
1475
|
-
|
1476
|
-
|
1477
|
-
|
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
|
-
|
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
|
-
|
1715
|
-
|
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
|
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
|
-
|
1726
|
-
|
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
|
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'] =
|
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'] =
|
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
|
-
|
1811
|
-
|
1812
|
-
|
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
|
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 [
|
1817
|
-
:returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
|
2245
|
-
|
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
|
-
|
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 =
|
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,
|
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,
|
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
|
-
|
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
|
-
|
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
|
-
|
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':
|
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
|
-
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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'
|
3352
|
+
until = self.safe_integer_n(params, ['until'])
|
2759
3353
|
if until is not None:
|
2760
|
-
params = self.omit(params, ['until'
|
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'
|
3422
|
+
until = self.safe_integer_n(params, ['until'])
|
2829
3423
|
if until is not None:
|
2830
|
-
params = self.omit(params, ['until'
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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', '
|
2959
|
-
params = self.omit(params, ['until'
|
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
|
-
|
2970
|
-
|
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
|
-
|
2973
|
-
|
2974
|
-
|
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
|
-
|
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 =
|
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
|
-
|
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,
|
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'
|
3706
|
+
until = self.safe_integer_n(params, ['until'])
|
3087
3707
|
if until is not None:
|
3088
|
-
params = self.omit(params, ['until'
|
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
|
-
|
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 =
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
3599
|
-
|
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
|
-
'
|
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
|