ccxt 4.2.76__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 +25 -0
- ccxt/abstract/kucoinfutures.py +35 -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 +3513 -1511
- 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 +3105 -881
- 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 +239 -50
- ccxt/async_support/bitget.py +1513 -563
- ccxt/async_support/bithumb.py +201 -67
- 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 +403 -150
- 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 +2326 -1255
- ccxt/async_support/cex.py +1409 -1329
- ccxt/async_support/coinbase.py +1455 -288
- 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 +467 -158
- ccxt/async_support/deribit.py +558 -324
- 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 +1473 -464
- 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 +1634 -269
- 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 +1050 -355
- 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 +1777 -455
- 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 +1155 -295
- 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 +1729 -482
- 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 +3513 -1511
- ccxt/binancecoinm.py +2 -1
- ccxt/binanceus.py +12 -1
- ccxt/binanceusdm.py +3 -1
- ccxt/bingx.py +3105 -881
- 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 +239 -50
- ccxt/bitget.py +1513 -563
- ccxt/bithumb.py +200 -67
- 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 +403 -150
- ccxt/btcalpha.py +161 -55
- ccxt/btcbox.py +250 -34
- ccxt/btcmarkets.py +232 -85
- ccxt/btcturk.py +159 -60
- ccxt/bybit.py +2326 -1255
- ccxt/cex.py +1408 -1329
- ccxt/coinbase.py +1455 -288
- 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 +467 -158
- ccxt/deribit.py +558 -324
- ccxt/digifinex.py +340 -223
- ccxt/ellipx.py +1826 -0
- ccxt/exmo.py +259 -128
- ccxt/gate.py +1473 -464
- 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 +1633 -269
- 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 +1050 -355
- 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 +1777 -455
- 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 +63 -15
- 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 +204 -82
- 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 +967 -661
- 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 +168 -32
- ccxt/pro/exmo.py +253 -21
- 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 +93 -34
- ccxt/pro/poloniex.py +129 -50
- ccxt/pro/poloniexfutures.py +53 -32
- ccxt/pro/probit.py +93 -86
- 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 +486 -70
- 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} +465 -407
- ccxt/test/tests_helpers.py +285 -0
- ccxt/test/tests_init.py +39 -0
- ccxt/test/{test_sync.py → tests_sync.py} +465 -409
- 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 +1155 -295
- 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.76.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.76.dist-info/METADATA +0 -626
- ccxt-4.2.76.dist-info/RECORD +0 -534
- {ccxt-4.2.76.dist-info → ccxt-4.4.48.dist-info}/top_level.txt +0 -0
ccxt/pro/blofin.py
ADDED
@@ -0,0 +1,692 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
4
|
+
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
5
|
+
|
6
|
+
import ccxt.async_support
|
7
|
+
from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheBySymbolBySide, ArrayCacheByTimestamp
|
8
|
+
import hashlib
|
9
|
+
from ccxt.base.types import Any, Balances, Int, Market, Order, OrderBook, Position, Str, Strings, Ticker, Tickers, Trade
|
10
|
+
from ccxt.async_support.base.ws.client import Client
|
11
|
+
from typing import List
|
12
|
+
from ccxt.base.errors import ExchangeError
|
13
|
+
from ccxt.base.errors import ArgumentsRequired
|
14
|
+
from ccxt.base.errors import NotSupported
|
15
|
+
|
16
|
+
|
17
|
+
class blofin(ccxt.async_support.blofin):
|
18
|
+
|
19
|
+
def describe(self):
|
20
|
+
return self.deep_extend(super(blofin, self).describe(), {
|
21
|
+
'has': {
|
22
|
+
'ws': True,
|
23
|
+
'watchTrades': True,
|
24
|
+
'watchTradesForSymbols': True,
|
25
|
+
'watchOrderBook': True,
|
26
|
+
'watchOrderBookForSymbols': True,
|
27
|
+
'watchTicker': True,
|
28
|
+
'watchTickers': True,
|
29
|
+
'watchBidsAsks': True,
|
30
|
+
'watchOHLCV': True,
|
31
|
+
'watchOHLCVForSymbols': True,
|
32
|
+
'watchOrders': True,
|
33
|
+
'watchOrdersForSymbols': True,
|
34
|
+
'watchPositions': True,
|
35
|
+
},
|
36
|
+
'urls': {
|
37
|
+
'api': {
|
38
|
+
'ws': {
|
39
|
+
'swap': {
|
40
|
+
'public': 'wss://openapi.blofin.com/ws/public',
|
41
|
+
'private': 'wss://openapi.blofin.com/ws/private',
|
42
|
+
},
|
43
|
+
},
|
44
|
+
},
|
45
|
+
},
|
46
|
+
'options': {
|
47
|
+
'defaultType': 'swap',
|
48
|
+
'tradesLimit': 1000,
|
49
|
+
# orderbook channel can be one from:
|
50
|
+
# - "books": 200 depth levels will be pushed in the initial full snapshot. Incremental data will be pushed every 100 ms for the changes in the order book during that period of time.
|
51
|
+
# - "books5": 5 depth levels snapshot will be pushed every time. Snapshot data will be pushed every 100 ms when there are changes in the 5 depth levels snapshot.
|
52
|
+
'watchOrderBook': {
|
53
|
+
'channel': 'books',
|
54
|
+
},
|
55
|
+
'watchOrderBookForSymbols': {
|
56
|
+
'channel': 'books',
|
57
|
+
},
|
58
|
+
},
|
59
|
+
'streaming': {
|
60
|
+
'ping': self.ping,
|
61
|
+
'keepAlive': 25000, # 30 seconds max
|
62
|
+
},
|
63
|
+
})
|
64
|
+
|
65
|
+
def ping(self, client):
|
66
|
+
return 'ping'
|
67
|
+
|
68
|
+
def handle_pong(self, client: Client, message):
|
69
|
+
#
|
70
|
+
# 'pong'
|
71
|
+
#
|
72
|
+
client.lastPong = self.milliseconds()
|
73
|
+
|
74
|
+
async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
75
|
+
"""
|
76
|
+
get the list of most recent trades for a particular symbol
|
77
|
+
|
78
|
+
https://docs.blofin.com/index.html#ws-trades-channel
|
79
|
+
|
80
|
+
:param str symbol: unified symbol of the market to fetch trades for
|
81
|
+
:param int [since]: timestamp in ms of the earliest trade to fetch
|
82
|
+
:param int [limit]: the maximum amount of trades to fetch
|
83
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
84
|
+
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
85
|
+
"""
|
86
|
+
params['callerMethodName'] = 'watchTrades'
|
87
|
+
return await self.watch_trades_for_symbols([symbol], since, limit, params)
|
88
|
+
|
89
|
+
async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
90
|
+
"""
|
91
|
+
get the list of most recent trades for a list of symbols
|
92
|
+
|
93
|
+
https://docs.blofin.com/index.html#ws-trades-channel
|
94
|
+
|
95
|
+
:param str[] symbols: unified symbol of the market to fetch trades for
|
96
|
+
:param int [since]: timestamp in ms of the earliest trade to fetch
|
97
|
+
:param int [limit]: the maximum amount of trades to fetch
|
98
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
99
|
+
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
100
|
+
"""
|
101
|
+
await self.load_markets()
|
102
|
+
trades = await self.watch_multiple_wrapper(True, 'trades', 'watchTradesForSymbols', symbols, params)
|
103
|
+
if self.newUpdates:
|
104
|
+
firstMarket = self.safe_dict(trades, 0)
|
105
|
+
firstSymbol = self.safe_string(firstMarket, 'symbol')
|
106
|
+
limit = trades.getLimit(firstSymbol, limit)
|
107
|
+
return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
|
108
|
+
|
109
|
+
def handle_trades(self, client: Client, message):
|
110
|
+
#
|
111
|
+
# {
|
112
|
+
# arg: {
|
113
|
+
# channel: "trades",
|
114
|
+
# instId: "DOGE-USDT",
|
115
|
+
# },
|
116
|
+
# data : [
|
117
|
+
# <same object in REST example>,
|
118
|
+
# ...
|
119
|
+
# ]
|
120
|
+
# }
|
121
|
+
#
|
122
|
+
arg = self.safe_dict(message, 'arg')
|
123
|
+
channelName = self.safe_string(arg, 'channel')
|
124
|
+
data = self.safe_list(message, 'data')
|
125
|
+
if data is None:
|
126
|
+
return
|
127
|
+
for i in range(0, len(data)):
|
128
|
+
rawTrade = data[i]
|
129
|
+
trade = self.parse_ws_trade(rawTrade)
|
130
|
+
symbol = trade['symbol']
|
131
|
+
stored = self.safe_value(self.trades, symbol)
|
132
|
+
if stored is None:
|
133
|
+
limit = self.safe_integer(self.options, 'tradesLimit', 1000)
|
134
|
+
stored = ArrayCache(limit)
|
135
|
+
self.trades[symbol] = stored
|
136
|
+
stored.append(trade)
|
137
|
+
messageHash = channelName + ':' + symbol
|
138
|
+
client.resolve(stored, messageHash)
|
139
|
+
|
140
|
+
def parse_ws_trade(self, trade, market: Market = None) -> Trade:
|
141
|
+
return self.parse_trade(trade, market)
|
142
|
+
|
143
|
+
async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
|
144
|
+
"""
|
145
|
+
watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
146
|
+
|
147
|
+
https://docs.blofin.com/index.html#ws-order-book-channel
|
148
|
+
|
149
|
+
:param str symbol: unified symbol of the market to fetch the order book for
|
150
|
+
:param int [limit]: the maximum amount of order book entries to return
|
151
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
152
|
+
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
|
153
|
+
"""
|
154
|
+
params['callerMethodName'] = 'watchOrderBook'
|
155
|
+
return await self.watch_order_book_for_symbols([symbol], limit, params)
|
156
|
+
|
157
|
+
async def watch_order_book_for_symbols(self, symbols: List[str], limit: Int = None, params={}) -> OrderBook:
|
158
|
+
"""
|
159
|
+
watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
160
|
+
|
161
|
+
https://docs.blofin.com/index.html#ws-order-book-channel
|
162
|
+
|
163
|
+
:param str[] symbols: unified array of symbols
|
164
|
+
:param int [limit]: the maximum amount of order book entries to return
|
165
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
166
|
+
:param str [params.depth]: the type of order book to subscribe to, default is 'depth/increase100', also accepts 'depth5' or 'depth20' or depth50
|
167
|
+
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
|
168
|
+
"""
|
169
|
+
await self.load_markets()
|
170
|
+
callerMethodName = None
|
171
|
+
callerMethodName, params = self.handle_param_string(params, 'callerMethodName', 'watchOrderBookForSymbols')
|
172
|
+
channelName = None
|
173
|
+
channelName, params = self.handle_option_and_params(params, callerMethodName, 'channel', 'books')
|
174
|
+
# due to some problem, temporarily disable other channels
|
175
|
+
if channelName != 'books':
|
176
|
+
raise NotSupported(self.id + ' ' + callerMethodName + '() at self moment ' + channelName + ' is not supported, coming soon')
|
177
|
+
orderbook = await self.watch_multiple_wrapper(True, channelName, callerMethodName, symbols, params)
|
178
|
+
return orderbook.limit()
|
179
|
+
|
180
|
+
def handle_order_book(self, client: Client, message):
|
181
|
+
#
|
182
|
+
# {
|
183
|
+
# arg: {
|
184
|
+
# channel: "books",
|
185
|
+
# instId: "DOGE-USDT",
|
186
|
+
# },
|
187
|
+
# action: "snapshot", # can be 'snapshot' or 'update'
|
188
|
+
# data: {
|
189
|
+
# asks: [ [0.08096, 1], [0.08097, 123], ... ],
|
190
|
+
# bids: [ [0.08095, 4], [0.08094, 237], ... ],
|
191
|
+
# ts: "1707491587909",
|
192
|
+
# prevSeqId: "0", # in case of 'update' there will be some value, less then seqId
|
193
|
+
# seqId: "3374250786",
|
194
|
+
# },
|
195
|
+
# }
|
196
|
+
#
|
197
|
+
arg = self.safe_dict(message, 'arg')
|
198
|
+
channelName = self.safe_string(arg, 'channel')
|
199
|
+
data = self.safe_dict(message, 'data')
|
200
|
+
marketId = self.safe_string(arg, 'instId')
|
201
|
+
market = self.safe_market(marketId)
|
202
|
+
symbol = market['symbol']
|
203
|
+
messageHash = channelName + ':' + symbol
|
204
|
+
if not (symbol in self.orderbooks):
|
205
|
+
self.orderbooks[symbol] = self.order_book()
|
206
|
+
orderbook = self.orderbooks[symbol]
|
207
|
+
timestamp = self.safe_integer(data, 'ts')
|
208
|
+
action = self.safe_string(message, 'action')
|
209
|
+
if action == 'snapshot':
|
210
|
+
orderBookSnapshot = self.parse_order_book(data, symbol, timestamp)
|
211
|
+
orderBookSnapshot['nonce'] = self.safe_integer(data, 'seqId')
|
212
|
+
orderbook.reset(orderBookSnapshot)
|
213
|
+
else:
|
214
|
+
asks = self.safe_list(data, 'asks', [])
|
215
|
+
bids = self.safe_list(data, 'bids', [])
|
216
|
+
self.handle_deltas_with_keys(orderbook['asks'], asks)
|
217
|
+
self.handle_deltas_with_keys(orderbook['bids'], bids)
|
218
|
+
orderbook['timestamp'] = timestamp
|
219
|
+
orderbook['datetime'] = self.iso8601(timestamp)
|
220
|
+
self.orderbooks[symbol] = orderbook
|
221
|
+
client.resolve(orderbook, messageHash)
|
222
|
+
|
223
|
+
async def watch_ticker(self, symbol: str, params={}) -> Ticker:
|
224
|
+
"""
|
225
|
+
watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
226
|
+
|
227
|
+
https://docs.blofin.com/index.html#ws-tickers-channel
|
228
|
+
|
229
|
+
:param str symbol: unified symbol of the market to fetch the ticker for
|
230
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
231
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
232
|
+
"""
|
233
|
+
params['callerMethodName'] = 'watchTicker'
|
234
|
+
market = self.market(symbol)
|
235
|
+
symbol = market['symbol']
|
236
|
+
result = await self.watch_tickers([symbol], params)
|
237
|
+
return result[symbol]
|
238
|
+
|
239
|
+
async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
|
240
|
+
"""
|
241
|
+
watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
|
242
|
+
|
243
|
+
https://docs.blofin.com/index.html#ws-tickers-channel
|
244
|
+
|
245
|
+
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
246
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
247
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
248
|
+
"""
|
249
|
+
if symbols is None:
|
250
|
+
raise NotSupported(self.id + ' watchTickers() requires a list of symbols')
|
251
|
+
ticker = await self.watch_multiple_wrapper(True, 'tickers', 'watchTickers', symbols, params)
|
252
|
+
if self.newUpdates:
|
253
|
+
tickers = {}
|
254
|
+
tickers[ticker['symbol']] = ticker
|
255
|
+
return tickers
|
256
|
+
return self.filter_by_array(self.tickers, 'symbol', symbols)
|
257
|
+
|
258
|
+
def handle_ticker(self, client: Client, message):
|
259
|
+
#
|
260
|
+
# message
|
261
|
+
#
|
262
|
+
# {
|
263
|
+
# arg: {
|
264
|
+
# channel: "tickers",
|
265
|
+
# instId: "DOGE-USDT",
|
266
|
+
# },
|
267
|
+
# data: [
|
268
|
+
# <same object in REST example>
|
269
|
+
# ],
|
270
|
+
# }
|
271
|
+
#
|
272
|
+
self.handle_bid_ask(client, message)
|
273
|
+
arg = self.safe_dict(message, 'arg')
|
274
|
+
channelName = self.safe_string(arg, 'channel')
|
275
|
+
data = self.safe_list(message, 'data')
|
276
|
+
for i in range(0, len(data)):
|
277
|
+
ticker = self.parse_ws_ticker(data[i])
|
278
|
+
symbol = ticker['symbol']
|
279
|
+
messageHash = channelName + ':' + symbol
|
280
|
+
self.tickers[symbol] = ticker
|
281
|
+
client.resolve(self.tickers[symbol], messageHash)
|
282
|
+
|
283
|
+
def parse_ws_ticker(self, ticker, market: Market = None) -> Ticker:
|
284
|
+
return self.parse_ticker(ticker, market)
|
285
|
+
|
286
|
+
async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
|
287
|
+
"""
|
288
|
+
watches best bid & ask for symbols
|
289
|
+
|
290
|
+
https://docs.blofin.com/index.html#ws-tickers-channel
|
291
|
+
|
292
|
+
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
293
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
294
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
295
|
+
"""
|
296
|
+
await self.load_markets()
|
297
|
+
symbols = self.market_symbols(symbols, None, False)
|
298
|
+
firstMarket = self.market(symbols[0])
|
299
|
+
channel = 'tickers'
|
300
|
+
marketType = None
|
301
|
+
marketType, params = self.handle_market_type_and_params('watchBidsAsks', firstMarket, params)
|
302
|
+
url = self.implode_hostname(self.urls['api']['ws'][marketType]['public'])
|
303
|
+
messageHashes = []
|
304
|
+
args = []
|
305
|
+
for i in range(0, len(symbols)):
|
306
|
+
market = self.market(symbols[i])
|
307
|
+
messageHashes.append('bidask:' + market['symbol'])
|
308
|
+
args.append({
|
309
|
+
'channel': channel,
|
310
|
+
'instId': market['id'],
|
311
|
+
})
|
312
|
+
request = self.get_subscription_request(args)
|
313
|
+
ticker = await self.watch_multiple(url, messageHashes, self.deep_extend(request, params), messageHashes)
|
314
|
+
if self.newUpdates:
|
315
|
+
tickers = {}
|
316
|
+
tickers[ticker['symbol']] = ticker
|
317
|
+
return tickers
|
318
|
+
return self.filter_by_array(self.bidsasks, 'symbol', symbols)
|
319
|
+
|
320
|
+
def handle_bid_ask(self, client: Client, message):
|
321
|
+
data = self.safe_list(message, 'data')
|
322
|
+
for i in range(0, len(data)):
|
323
|
+
ticker = self.parse_ws_bid_ask(data[i])
|
324
|
+
symbol = ticker['symbol']
|
325
|
+
messageHash = 'bidask:' + symbol
|
326
|
+
self.bidsasks[symbol] = ticker
|
327
|
+
client.resolve(ticker, messageHash)
|
328
|
+
|
329
|
+
def parse_ws_bid_ask(self, ticker, market=None):
|
330
|
+
marketId = self.safe_string(ticker, 'instId')
|
331
|
+
market = self.safe_market(marketId, market, '-')
|
332
|
+
symbol = self.safe_string(market, 'symbol')
|
333
|
+
timestamp = self.safe_integer(ticker, 'ts')
|
334
|
+
return self.safe_ticker({
|
335
|
+
'symbol': symbol,
|
336
|
+
'timestamp': timestamp,
|
337
|
+
'datetime': self.iso8601(timestamp),
|
338
|
+
'ask': self.safe_string(ticker, 'askPrice'),
|
339
|
+
'askVolume': self.safe_string(ticker, 'askSize'),
|
340
|
+
'bid': self.safe_string(ticker, 'bidPrice'),
|
341
|
+
'bidVolume': self.safe_string(ticker, 'bidSize'),
|
342
|
+
'info': ticker,
|
343
|
+
}, market)
|
344
|
+
|
345
|
+
async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
346
|
+
"""
|
347
|
+
watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
348
|
+
:param str symbol: unified symbol of the market to fetch OHLCV data for
|
349
|
+
:param str timeframe: the length of time each candle represents
|
350
|
+
:param int [since]: timestamp in ms of the earliest candle to fetch
|
351
|
+
:param int [limit]: the maximum amount of candles to fetch
|
352
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
353
|
+
:returns int[][]: A list of candles ordered, open, high, low, close, volume
|
354
|
+
"""
|
355
|
+
params['callerMethodName'] = 'watchOHLCV'
|
356
|
+
result = await self.watch_ohlcv_for_symbols([[symbol, timeframe]], since, limit, params)
|
357
|
+
return result[symbol][timeframe]
|
358
|
+
|
359
|
+
async def watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], since: Int = None, limit: Int = None, params={}):
|
360
|
+
"""
|
361
|
+
watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
362
|
+
|
363
|
+
https://docs.blofin.com/index.html#ws-candlesticks-channel
|
364
|
+
|
365
|
+
:param str[][] symbolsAndTimeframes: array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
|
366
|
+
:param int [since]: timestamp in ms of the earliest candle to fetch
|
367
|
+
:param int [limit]: the maximum amount of candles to fetch
|
368
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
369
|
+
:returns int[][]: A list of candles ordered, open, high, low, close, volume
|
370
|
+
"""
|
371
|
+
symbolsLength = len(symbolsAndTimeframes)
|
372
|
+
if symbolsLength == 0 or not isinstance(symbolsAndTimeframes[0], list):
|
373
|
+
raise ArgumentsRequired(self.id + " watchOHLCVForSymbols() requires a an array of symbols and timeframes, like [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]")
|
374
|
+
await self.load_markets()
|
375
|
+
symbol, timeframe, candles = await self.watch_multiple_wrapper(True, 'candle', 'watchOHLCVForSymbols', symbolsAndTimeframes, params)
|
376
|
+
if self.newUpdates:
|
377
|
+
limit = candles.getLimit(symbol, limit)
|
378
|
+
filtered = self.filter_by_since_limit(candles, since, limit, 0, True)
|
379
|
+
return self.create_ohlcv_object(symbol, timeframe, filtered)
|
380
|
+
|
381
|
+
def handle_ohlcv(self, client: Client, message):
|
382
|
+
#
|
383
|
+
# message
|
384
|
+
#
|
385
|
+
# {
|
386
|
+
# arg: {
|
387
|
+
# channel: "candle1m",
|
388
|
+
# instId: "DOGE-USDT",
|
389
|
+
# },
|
390
|
+
# data: [
|
391
|
+
# [same object in REST example]
|
392
|
+
# ],
|
393
|
+
# }
|
394
|
+
#
|
395
|
+
arg = self.safe_dict(message, 'arg')
|
396
|
+
channelName = self.safe_string(arg, 'channel')
|
397
|
+
data = self.safe_list(message, 'data')
|
398
|
+
marketId = self.safe_string(arg, 'instId')
|
399
|
+
market = self.safe_market(marketId)
|
400
|
+
symbol = market['symbol']
|
401
|
+
interval = channelName.replace('candle', '')
|
402
|
+
unifiedTimeframe = self.find_timeframe(interval)
|
403
|
+
self.ohlcvs[symbol] = self.safe_dict(self.ohlcvs, symbol, {})
|
404
|
+
stored = self.safe_value(self.ohlcvs[symbol], unifiedTimeframe)
|
405
|
+
if stored is None:
|
406
|
+
limit = self.safe_integer(self.options, 'OHLCVLimit', 1000)
|
407
|
+
stored = ArrayCacheByTimestamp(limit)
|
408
|
+
self.ohlcvs[symbol][unifiedTimeframe] = stored
|
409
|
+
for i in range(0, len(data)):
|
410
|
+
candle = data[i]
|
411
|
+
parsed = self.parse_ohlcv(candle, market)
|
412
|
+
stored.append(parsed)
|
413
|
+
resolveData = [symbol, unifiedTimeframe, stored]
|
414
|
+
messageHash = 'candle' + interval + ':' + symbol
|
415
|
+
client.resolve(resolveData, messageHash)
|
416
|
+
|
417
|
+
async def watch_balance(self, params={}) -> Balances:
|
418
|
+
"""
|
419
|
+
query for balance and get the amount of funds available for trading or funds locked in orders
|
420
|
+
|
421
|
+
https://docs.blofin.com/index.html#ws-account-channel
|
422
|
+
|
423
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
424
|
+
:returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
|
425
|
+
"""
|
426
|
+
await self.load_markets()
|
427
|
+
await self.authenticate()
|
428
|
+
marketType = None
|
429
|
+
marketType, params = self.handle_market_type_and_params('watchBalance', None, params)
|
430
|
+
if marketType == 'spot':
|
431
|
+
raise NotSupported(self.id + ' watchBalance() is not supported for spot markets yet')
|
432
|
+
messageHash = marketType + ':balance'
|
433
|
+
sub = {
|
434
|
+
'channel': 'account',
|
435
|
+
}
|
436
|
+
request = self.get_subscription_request([sub])
|
437
|
+
url = self.implode_hostname(self.urls['api']['ws'][marketType]['private'])
|
438
|
+
return await self.watch(url, messageHash, self.deep_extend(request, params), messageHash)
|
439
|
+
|
440
|
+
def handle_balance(self, client: Client, message):
|
441
|
+
#
|
442
|
+
# {
|
443
|
+
# arg: {
|
444
|
+
# channel: "account",
|
445
|
+
# },
|
446
|
+
# data: <same object in REST example>,
|
447
|
+
# }
|
448
|
+
#
|
449
|
+
marketType = 'swap' # for now
|
450
|
+
if not (marketType in self.balance):
|
451
|
+
self.balance[marketType] = {}
|
452
|
+
self.balance[marketType] = self.parse_ws_balance(message)
|
453
|
+
messageHash = marketType + ':balance'
|
454
|
+
client.resolve(self.balance[marketType], messageHash)
|
455
|
+
|
456
|
+
def parse_ws_balance(self, message):
|
457
|
+
return self.parse_balance(message)
|
458
|
+
|
459
|
+
async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
460
|
+
"""
|
461
|
+
watches information on multiple orders made by the user
|
462
|
+
:param str symbol: unified market symbol of the market orders were made in
|
463
|
+
:param int [since]: the earliest time in ms to fetch orders for
|
464
|
+
:param int [limit]: the maximum number of order structures to retrieve
|
465
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
466
|
+
:returns dict[]: a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure
|
467
|
+
"""
|
468
|
+
params['callerMethodName'] = 'watchOrders'
|
469
|
+
symbolsArray = [symbol] if (symbol is not None) else []
|
470
|
+
return await self.watch_orders_for_symbols(symbolsArray, since, limit, params)
|
471
|
+
|
472
|
+
async def watch_orders_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
473
|
+
"""
|
474
|
+
watches information on multiple orders made by the user across multiple symbols
|
475
|
+
|
476
|
+
https://docs.blofin.com/index.html#ws-order-channel
|
477
|
+
|
478
|
+
:param str[] symbols:
|
479
|
+
:param int [since]: the earliest time in ms to fetch orders for
|
480
|
+
:param int [limit]: the maximum number of order structures to retrieve
|
481
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
482
|
+
:returns dict[]: a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure
|
483
|
+
"""
|
484
|
+
await self.authenticate()
|
485
|
+
await self.load_markets()
|
486
|
+
orders = await self.watch_multiple_wrapper(False, 'orders', 'watchOrdersForSymbols', symbols, params)
|
487
|
+
if self.newUpdates:
|
488
|
+
first = self.safe_value(orders, 0)
|
489
|
+
tradeSymbol = self.safe_string(first, 'symbol')
|
490
|
+
limit = orders.getLimit(tradeSymbol, limit)
|
491
|
+
return self.filter_by_since_limit(orders, since, limit, 'timestamp', True)
|
492
|
+
|
493
|
+
def handle_orders(self, client: Client, message):
|
494
|
+
#
|
495
|
+
# {
|
496
|
+
# action: 'update',
|
497
|
+
# arg: {channel: 'orders'},
|
498
|
+
# data: [
|
499
|
+
# <same object in REST example>
|
500
|
+
# ]
|
501
|
+
# }
|
502
|
+
#
|
503
|
+
if self.orders is None:
|
504
|
+
limit = self.safe_integer(self.options, 'ordersLimit', 1000)
|
505
|
+
self.orders = ArrayCacheBySymbolById(limit)
|
506
|
+
orders = self.orders
|
507
|
+
arg = self.safe_dict(message, 'arg')
|
508
|
+
channelName = self.safe_string(arg, 'channel')
|
509
|
+
data = self.safe_list(message, 'data')
|
510
|
+
for i in range(0, len(data)):
|
511
|
+
order = self.parse_ws_order(data[i])
|
512
|
+
symbol = order['symbol']
|
513
|
+
messageHash = channelName + ':' + symbol
|
514
|
+
orders.append(order)
|
515
|
+
client.resolve(orders, messageHash)
|
516
|
+
client.resolve(orders, channelName)
|
517
|
+
|
518
|
+
def parse_ws_order(self, order, market: Market = None) -> Order:
|
519
|
+
return self.parse_order(order, market)
|
520
|
+
|
521
|
+
async def watch_positions(self, symbols: Strings = None, since: Int = None, limit: Int = None, params={}) -> List[Position]:
|
522
|
+
"""
|
523
|
+
|
524
|
+
https://docs.blofin.com/index.html#ws-positions-channel
|
525
|
+
|
526
|
+
watch all open positions
|
527
|
+
:param str[]|None symbols: list of unified market symbols
|
528
|
+
:param int [since]: the earliest time in ms to fetch positions for
|
529
|
+
:param int [limit]: the maximum number of positions to retrieve
|
530
|
+
:param dict params: extra parameters specific to the exchange API endpoint
|
531
|
+
:returns dict[]: a list of `position structure <https://docs.ccxt.com/en/latest/manual.html#position-structure>`
|
532
|
+
"""
|
533
|
+
await self.authenticate()
|
534
|
+
await self.load_markets()
|
535
|
+
newPositions = await self.watch_multiple_wrapper(False, 'positions', 'watchPositions', symbols, params)
|
536
|
+
if self.newUpdates:
|
537
|
+
return newPositions
|
538
|
+
return self.filter_by_symbols_since_limit(self.positions, symbols, since, limit)
|
539
|
+
|
540
|
+
def handle_positions(self, client: Client, message):
|
541
|
+
#
|
542
|
+
# {
|
543
|
+
# arg: {channel: 'positions'},
|
544
|
+
# data: [
|
545
|
+
# <same object in REST example>
|
546
|
+
# ]
|
547
|
+
# }
|
548
|
+
#
|
549
|
+
if self.positions is None:
|
550
|
+
self.positions = ArrayCacheBySymbolBySide()
|
551
|
+
cache = self.positions
|
552
|
+
arg = self.safe_dict(message, 'arg')
|
553
|
+
channelName = self.safe_string(arg, 'channel')
|
554
|
+
data = self.safe_list(message, 'data')
|
555
|
+
newPositions = []
|
556
|
+
for i in range(0, len(data)):
|
557
|
+
position = self.parse_ws_position(data[i])
|
558
|
+
newPositions.append(position)
|
559
|
+
cache.append(position)
|
560
|
+
messageHash = channelName + ':' + position['symbol']
|
561
|
+
client.resolve(position, messageHash)
|
562
|
+
|
563
|
+
def parse_ws_position(self, position, market: Market = None) -> Position:
|
564
|
+
return self.parse_position(position, market)
|
565
|
+
|
566
|
+
async def watch_multiple_wrapper(self, isPublic: bool, channelName: str, callerMethodName: str, symbolsArray: List[Any] = None, params={}):
|
567
|
+
# underlier method for all watch-multiple symbols
|
568
|
+
await self.load_markets()
|
569
|
+
callerMethodName, params = self.handle_param_string(params, 'callerMethodName', callerMethodName)
|
570
|
+
# if OHLCV method are being called, then symbols would be symbolsAndTimeframes(multi-dimensional) array
|
571
|
+
isOHLCV = (channelName == 'candle')
|
572
|
+
symbols = self.get_list_from_object_values(symbolsArray, 0) if isOHLCV else symbolsArray
|
573
|
+
symbols = self.market_symbols(symbols, None, True, True)
|
574
|
+
firstMarket = None
|
575
|
+
firstSymbol = self.safe_string(symbols, 0)
|
576
|
+
if firstSymbol is not None:
|
577
|
+
firstMarket = self.market(firstSymbol)
|
578
|
+
marketType = None
|
579
|
+
marketType, params = self.handle_market_type_and_params(callerMethodName, firstMarket, params)
|
580
|
+
if marketType != 'swap':
|
581
|
+
raise NotSupported(self.id + ' ' + callerMethodName + '() does not support ' + marketType + ' markets yet')
|
582
|
+
rawSubscriptions = []
|
583
|
+
messageHashes = []
|
584
|
+
if symbols is None:
|
585
|
+
symbols = []
|
586
|
+
symbolsLength = len(symbols)
|
587
|
+
if symbolsLength > 0:
|
588
|
+
for i in range(0, len(symbols)):
|
589
|
+
current = symbols[i]
|
590
|
+
market = None
|
591
|
+
channel = channelName
|
592
|
+
if isOHLCV:
|
593
|
+
market = self.market(current)
|
594
|
+
tfArray = symbolsArray[i]
|
595
|
+
tf = tfArray[1]
|
596
|
+
interval = self.safe_string(self.timeframes, tf, tf)
|
597
|
+
channel += interval
|
598
|
+
else:
|
599
|
+
market = self.market(current)
|
600
|
+
topic = {
|
601
|
+
'channel': channel,
|
602
|
+
'instId': market['id'],
|
603
|
+
}
|
604
|
+
rawSubscriptions.append(topic)
|
605
|
+
messageHashes.append(channel + ':' + market['symbol'])
|
606
|
+
else:
|
607
|
+
rawSubscriptions.append({'channel': channelName})
|
608
|
+
messageHashes.append(channelName)
|
609
|
+
# private channel are difference, they only need plural channel name for multiple symbols
|
610
|
+
if self.in_array(channelName, ['orders', 'positions']):
|
611
|
+
rawSubscriptions = [{'channel': channelName}]
|
612
|
+
request = self.get_subscription_request(rawSubscriptions)
|
613
|
+
privateOrPublic = 'public' if isPublic else 'private'
|
614
|
+
url = self.implode_hostname(self.urls['api']['ws'][marketType][privateOrPublic])
|
615
|
+
return await self.watch_multiple(url, messageHashes, self.deep_extend(request, params), messageHashes)
|
616
|
+
|
617
|
+
def get_subscription_request(self, args):
|
618
|
+
return {
|
619
|
+
'op': 'subscribe',
|
620
|
+
'args': args,
|
621
|
+
}
|
622
|
+
|
623
|
+
def handle_message(self, client: Client, message):
|
624
|
+
#
|
625
|
+
# message examples
|
626
|
+
#
|
627
|
+
# {
|
628
|
+
# arg: {
|
629
|
+
# channel: "trades",
|
630
|
+
# instId: "DOGE-USDT",
|
631
|
+
# },
|
632
|
+
# event: "subscribe"
|
633
|
+
# }
|
634
|
+
#
|
635
|
+
# incoming data updates' examples can be seen under each handler method
|
636
|
+
#
|
637
|
+
methods = {
|
638
|
+
# public
|
639
|
+
'pong': self.handle_pong,
|
640
|
+
'trades': self.handle_trades,
|
641
|
+
'books': self.handle_order_book,
|
642
|
+
'tickers': self.handle_ticker,
|
643
|
+
'candle': self.handle_ohlcv, # candle1m, candle5m, etc
|
644
|
+
# private
|
645
|
+
'account': self.handle_balance,
|
646
|
+
'orders': self.handle_orders,
|
647
|
+
'positions': self.handle_positions,
|
648
|
+
}
|
649
|
+
method = None
|
650
|
+
if message == 'pong':
|
651
|
+
method = self.safe_value(methods, 'pong')
|
652
|
+
else:
|
653
|
+
event = self.safe_string(message, 'event')
|
654
|
+
if event == 'subscribe':
|
655
|
+
return
|
656
|
+
elif event == 'login':
|
657
|
+
future = self.safe_value(client.futures, 'authenticate_hash')
|
658
|
+
future.resolve(True)
|
659
|
+
return
|
660
|
+
elif event == 'error':
|
661
|
+
raise ExchangeError(self.id + ' error: ' + self.json(message))
|
662
|
+
arg = self.safe_dict(message, 'arg')
|
663
|
+
channelName = self.safe_string(arg, 'channel')
|
664
|
+
method = self.safe_value(methods, channelName)
|
665
|
+
if not method and channelName.find('candle') >= 0:
|
666
|
+
method = methods['candle']
|
667
|
+
if method:
|
668
|
+
method(client, message)
|
669
|
+
|
670
|
+
async def authenticate(self, params={}):
|
671
|
+
self.check_required_credentials()
|
672
|
+
milliseconds = self.milliseconds()
|
673
|
+
messageHash = 'authenticate_hash'
|
674
|
+
timestamp = str(milliseconds)
|
675
|
+
nonce = 'n_' + timestamp
|
676
|
+
auth = '/users/self/verify' + 'GET' + timestamp + '' + nonce
|
677
|
+
signature = self.string_to_base64(self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha256))
|
678
|
+
request = {
|
679
|
+
'op': 'login',
|
680
|
+
'args': [
|
681
|
+
{
|
682
|
+
'apiKey': self.apiKey,
|
683
|
+
'passphrase': self.password,
|
684
|
+
'timestamp': timestamp,
|
685
|
+
'nonce': nonce,
|
686
|
+
'sign': signature,
|
687
|
+
},
|
688
|
+
],
|
689
|
+
}
|
690
|
+
marketType = 'swap' # for now
|
691
|
+
url = self.implode_hostname(self.urls['api']['ws'][marketType]['private'])
|
692
|
+
await self.watch(url, messageHash, self.deep_extend(request, params), messageHash)
|