ccxt 4.2.77__py2.py3-none-any.whl → 4.4.49__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +3205 -937
- 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 +1525 -573
- 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 +223 -97
- 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 +639 -323
- ccxt/async_support/digifinex.py +465 -233
- ccxt/async_support/ellipx.py +1887 -0
- ccxt/async_support/exmo.py +317 -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 +433 -178
- ccxt/async_support/hollaex.py +207 -83
- ccxt/async_support/htx.py +1095 -563
- ccxt/async_support/huobijp.py +178 -56
- ccxt/async_support/hyperliquid.py +1678 -292
- ccxt/async_support/idex.py +219 -95
- ccxt/async_support/independentreserve.py +300 -31
- ccxt/async_support/indodax.py +226 -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 +198 -107
- ccxt/async_support/latoken.py +199 -79
- ccxt/async_support/lbank.py +360 -113
- ccxt/async_support/luno.py +185 -62
- ccxt/async_support/lykke.py +168 -55
- ccxt/async_support/mercado.py +101 -29
- ccxt/async_support/mexc.py +995 -429
- ccxt/async_support/myokx.py +53 -0
- ccxt/async_support/ndax.py +234 -82
- ccxt/async_support/novadax.py +195 -75
- ccxt/async_support/oceanex.py +244 -59
- ccxt/async_support/okcoin.py +301 -165
- ccxt/async_support/okx.py +1776 -454
- ccxt/async_support/onetrading.py +198 -414
- ccxt/async_support/oxfun.py +2898 -0
- ccxt/async_support/p2b.py +142 -52
- ccxt/async_support/paradex.py +2085 -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 +3205 -937
- 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 +1525 -573
- 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 +223 -97
- 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 +639 -323
- ccxt/digifinex.py +465 -233
- ccxt/ellipx.py +1887 -0
- ccxt/exmo.py +317 -128
- ccxt/gate.py +1472 -463
- ccxt/gemini.py +206 -84
- ccxt/hashkey.py +4164 -0
- ccxt/hitbtc.py +433 -178
- ccxt/hollaex.py +207 -83
- ccxt/htx.py +1095 -563
- ccxt/huobijp.py +178 -56
- ccxt/hyperliquid.py +1677 -292
- ccxt/idex.py +219 -95
- ccxt/independentreserve.py +299 -31
- ccxt/indodax.py +226 -62
- ccxt/kraken.py +871 -354
- ccxt/krakenfutures.py +324 -100
- ccxt/kucoin.py +917 -357
- ccxt/kucoinfutures.py +1004 -149
- ccxt/kuna.py +198 -107
- ccxt/latoken.py +199 -79
- ccxt/lbank.py +360 -113
- ccxt/luno.py +185 -62
- ccxt/lykke.py +168 -55
- ccxt/mercado.py +101 -29
- ccxt/mexc.py +994 -429
- ccxt/myokx.py +53 -0
- ccxt/ndax.py +234 -82
- ccxt/novadax.py +195 -75
- ccxt/oceanex.py +244 -59
- ccxt/okcoin.py +301 -165
- ccxt/okx.py +1776 -454
- ccxt/onetrading.py +198 -414
- ccxt/oxfun.py +2897 -0
- ccxt/p2b.py +142 -52
- ccxt/paradex.py +2085 -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 +143 -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.49.dist-info/LICENSE.txt +21 -0
- ccxt-4.4.49.dist-info/METADATA +646 -0
- ccxt-4.4.49.dist-info/RECORD +669 -0
- {ccxt-4.2.77.dist-info → ccxt-4.4.49.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.49.dist-info}/top_level.txt +0 -0
ccxt/pro/bitfinex.py
CHANGED
@@ -4,13 +4,14 @@
|
|
4
4
|
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
5
5
|
|
6
6
|
import ccxt.async_support
|
7
|
-
from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById
|
7
|
+
from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheByTimestamp
|
8
8
|
import hashlib
|
9
|
-
from ccxt.base.types import Int, Order, OrderBook, Str, Ticker, Trade
|
9
|
+
from ccxt.base.types import Balances, Int, Order, OrderBook, Str, Ticker, Trade
|
10
10
|
from ccxt.async_support.base.ws.client import Client
|
11
11
|
from typing import List
|
12
12
|
from ccxt.base.errors import ExchangeError
|
13
13
|
from ccxt.base.errors import AuthenticationError
|
14
|
+
from ccxt.base.errors import ChecksumError
|
14
15
|
from ccxt.base.precise import Precise
|
15
16
|
|
16
17
|
|
@@ -24,14 +25,17 @@ class bitfinex(ccxt.async_support.bitfinex):
|
|
24
25
|
'watchTickers': False,
|
25
26
|
'watchOrderBook': True,
|
26
27
|
'watchTrades': True,
|
27
|
-
'
|
28
|
-
'
|
28
|
+
'watchTradesForSymbols': False,
|
29
|
+
'watchMyTrades': True,
|
30
|
+
'watchBalance': True,
|
31
|
+
'watchOHLCV': True,
|
32
|
+
'watchOrders': True,
|
29
33
|
},
|
30
34
|
'urls': {
|
31
35
|
'api': {
|
32
36
|
'ws': {
|
33
|
-
'public': 'wss://api-pub.bitfinex.com/ws/
|
34
|
-
'private': 'wss://api.bitfinex.com/ws/
|
37
|
+
'public': 'wss://api-pub.bitfinex.com/ws/2',
|
38
|
+
'private': 'wss://api.bitfinex.com/ws/2',
|
35
39
|
},
|
36
40
|
},
|
37
41
|
},
|
@@ -39,6 +43,7 @@ class bitfinex(ccxt.async_support.bitfinex):
|
|
39
43
|
'watchOrderBook': {
|
40
44
|
'prec': 'P0',
|
41
45
|
'freq': 'F0',
|
46
|
+
'checksum': True,
|
42
47
|
},
|
43
48
|
'ordersLimit': 1000,
|
44
49
|
},
|
@@ -49,15 +54,136 @@ class bitfinex(ccxt.async_support.bitfinex):
|
|
49
54
|
market = self.market(symbol)
|
50
55
|
marketId = market['id']
|
51
56
|
url = self.urls['api']['ws']['public']
|
57
|
+
client = self.client(url)
|
52
58
|
messageHash = channel + ':' + marketId
|
53
|
-
|
54
|
-
request = {
|
59
|
+
request: dict = {
|
55
60
|
'event': 'subscribe',
|
56
61
|
'channel': channel,
|
57
62
|
'symbol': marketId,
|
58
|
-
'messageHash': messageHash,
|
59
63
|
}
|
60
|
-
|
64
|
+
result = await self.watch(url, messageHash, self.deep_extend(request, params), messageHash, {'checksum': False})
|
65
|
+
checksum = self.safe_bool(self.options, 'checksum', True)
|
66
|
+
if checksum and not client.subscriptions[messageHash]['checksum'] and (channel == 'book'):
|
67
|
+
client.subscriptions[messageHash]['checksum'] = True
|
68
|
+
await client.send({
|
69
|
+
'event': 'conf',
|
70
|
+
'flags': 131072,
|
71
|
+
})
|
72
|
+
return result
|
73
|
+
|
74
|
+
async def subscribe_private(self, messageHash):
|
75
|
+
await self.load_markets()
|
76
|
+
await self.authenticate()
|
77
|
+
url = self.urls['api']['ws']['private']
|
78
|
+
return await self.watch(url, messageHash, None, 1)
|
79
|
+
|
80
|
+
async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
81
|
+
"""
|
82
|
+
watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
83
|
+
:param str symbol: unified symbol of the market to fetch OHLCV data for
|
84
|
+
:param str timeframe: the length of time each candle represents
|
85
|
+
:param int [since]: timestamp in ms of the earliest candle to fetch
|
86
|
+
:param int [limit]: the maximum amount of candles to fetch
|
87
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
88
|
+
:returns int[][]: A list of candles ordered, open, high, low, close, volume
|
89
|
+
"""
|
90
|
+
await self.load_markets()
|
91
|
+
market = self.market(symbol)
|
92
|
+
symbol = market['symbol']
|
93
|
+
interval = self.safe_string(self.timeframes, timeframe, timeframe)
|
94
|
+
channel = 'candles'
|
95
|
+
key = 'trade:' + interval + ':' + market['id']
|
96
|
+
messageHash = channel + ':' + interval + ':' + market['id']
|
97
|
+
request: dict = {
|
98
|
+
'event': 'subscribe',
|
99
|
+
'channel': channel,
|
100
|
+
'key': key,
|
101
|
+
}
|
102
|
+
url = self.urls['api']['ws']['public']
|
103
|
+
# not using subscribe here because self message has a different format
|
104
|
+
ohlcv = await self.watch(url, messageHash, self.deep_extend(request, params), messageHash)
|
105
|
+
if self.newUpdates:
|
106
|
+
limit = ohlcv.getLimit(symbol, limit)
|
107
|
+
return self.filter_by_since_limit(ohlcv, since, limit, 0, True)
|
108
|
+
|
109
|
+
def handle_ohlcv(self, client: Client, message, subscription):
|
110
|
+
#
|
111
|
+
# initial snapshot
|
112
|
+
# [
|
113
|
+
# 341527, # channel id
|
114
|
+
# [
|
115
|
+
# [
|
116
|
+
# 1654705860000, # timestamp
|
117
|
+
# 1802.6, # open
|
118
|
+
# 1800.3, # close
|
119
|
+
# 1802.8, # high
|
120
|
+
# 1800.3, # low
|
121
|
+
# 86.49588236 # volume
|
122
|
+
# ],
|
123
|
+
# [
|
124
|
+
# 1654705800000,
|
125
|
+
# 1803.6,
|
126
|
+
# 1802.6,
|
127
|
+
# 1804.9,
|
128
|
+
# 1802.3,
|
129
|
+
# 74.6348086
|
130
|
+
# ],
|
131
|
+
# [
|
132
|
+
# 1654705740000,
|
133
|
+
# 1802.5,
|
134
|
+
# 1803.2,
|
135
|
+
# 1804.4,
|
136
|
+
# 1802.4,
|
137
|
+
# 23.61801085
|
138
|
+
# ]
|
139
|
+
# ]
|
140
|
+
# ]
|
141
|
+
#
|
142
|
+
# update
|
143
|
+
# [
|
144
|
+
# 211171,
|
145
|
+
# [
|
146
|
+
# 1654705680000,
|
147
|
+
# 1801,
|
148
|
+
# 1802.4,
|
149
|
+
# 1802.9,
|
150
|
+
# 1800.4,
|
151
|
+
# 23.91911091
|
152
|
+
# ]
|
153
|
+
# ]
|
154
|
+
#
|
155
|
+
data = self.safe_value(message, 1, [])
|
156
|
+
ohlcvs = None
|
157
|
+
first = self.safe_value(data, 0)
|
158
|
+
if isinstance(first, list):
|
159
|
+
# snapshot
|
160
|
+
ohlcvs = data
|
161
|
+
else:
|
162
|
+
# update
|
163
|
+
ohlcvs = [data]
|
164
|
+
channel = self.safe_value(subscription, 'channel')
|
165
|
+
key = self.safe_string(subscription, 'key')
|
166
|
+
keyParts = key.split(':')
|
167
|
+
interval = self.safe_string(keyParts, 1)
|
168
|
+
marketId = key
|
169
|
+
marketId = marketId.replace('trade:', '')
|
170
|
+
marketId = marketId.replace(interval + ':', '')
|
171
|
+
market = self.safe_market(marketId)
|
172
|
+
timeframe = self.find_timeframe(interval)
|
173
|
+
symbol = market['symbol']
|
174
|
+
messageHash = channel + ':' + interval + ':' + marketId
|
175
|
+
self.ohlcvs[symbol] = self.safe_value(self.ohlcvs, symbol, {})
|
176
|
+
stored = self.safe_value(self.ohlcvs[symbol], timeframe)
|
177
|
+
if stored is None:
|
178
|
+
limit = self.safe_integer(self.options, 'OHLCVLimit', 1000)
|
179
|
+
stored = ArrayCacheByTimestamp(limit)
|
180
|
+
self.ohlcvs[symbol][timeframe] = stored
|
181
|
+
ohlcvsLength = len(ohlcvs)
|
182
|
+
for i in range(0, ohlcvsLength):
|
183
|
+
ohlcv = ohlcvs[ohlcvsLength - i - 1]
|
184
|
+
parsed = self.parse_ohlcv(ohlcv, market)
|
185
|
+
stored.append(parsed)
|
186
|
+
client.resolve(stored, messageHash)
|
61
187
|
|
62
188
|
async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
63
189
|
"""
|
@@ -68,13 +194,30 @@ class bitfinex(ccxt.async_support.bitfinex):
|
|
68
194
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
69
195
|
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
70
196
|
"""
|
71
|
-
await self.load_markets()
|
72
|
-
symbol = self.symbol(symbol)
|
73
197
|
trades = await self.subscribe('trades', symbol, params)
|
74
198
|
if self.newUpdates:
|
75
199
|
limit = trades.getLimit(symbol, limit)
|
76
200
|
return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
|
77
201
|
|
202
|
+
async def watch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
203
|
+
"""
|
204
|
+
watches information on multiple trades made by the user
|
205
|
+
:param str symbol: unified market symbol of the market trades were made in
|
206
|
+
:param int [since]: the earliest time in ms to fetch trades for
|
207
|
+
:param int [limit]: the maximum number of trade structures to retrieve
|
208
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
209
|
+
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
|
210
|
+
"""
|
211
|
+
await self.load_markets()
|
212
|
+
messageHash = 'myTrade'
|
213
|
+
if symbol is not None:
|
214
|
+
market = self.market(symbol)
|
215
|
+
messageHash += ':' + market['id']
|
216
|
+
trades = await self.subscribe_private(messageHash)
|
217
|
+
if self.newUpdates:
|
218
|
+
limit = trades.getLimit(symbol, limit)
|
219
|
+
return self.filter_by_symbol_since_limit(trades, symbol, since, limit, True)
|
220
|
+
|
78
221
|
async def watch_ticker(self, symbol: str, params={}) -> Ticker:
|
79
222
|
"""
|
80
223
|
watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
@@ -84,91 +227,188 @@ class bitfinex(ccxt.async_support.bitfinex):
|
|
84
227
|
"""
|
85
228
|
return await self.subscribe('ticker', symbol, params)
|
86
229
|
|
87
|
-
def
|
88
|
-
#
|
89
|
-
# initial snapshot
|
230
|
+
def handle_my_trade(self, client: Client, message, subscription={}):
|
90
231
|
#
|
232
|
+
# trade execution
|
233
|
+
# [
|
234
|
+
# 0,
|
235
|
+
# "te", # or tu
|
91
236
|
# [
|
92
|
-
#
|
93
|
-
#
|
94
|
-
#
|
95
|
-
#
|
96
|
-
#
|
97
|
-
#
|
237
|
+
# 1133411090,
|
238
|
+
# "tLTCUST",
|
239
|
+
# 1655110144598,
|
240
|
+
# 97084883506,
|
241
|
+
# 0.1,
|
242
|
+
# 42.821,
|
243
|
+
# "EXCHANGE MARKET",
|
244
|
+
# 42.799,
|
245
|
+
# -1,
|
246
|
+
# null,
|
247
|
+
# null,
|
248
|
+
# 1655110144596
|
98
249
|
# ]
|
250
|
+
# ]
|
99
251
|
#
|
100
|
-
|
252
|
+
name = 'myTrade'
|
253
|
+
data = self.safe_value(message, 2)
|
254
|
+
trade = self.parse_ws_trade(data)
|
255
|
+
symbol = trade['symbol']
|
256
|
+
market = self.market(symbol)
|
257
|
+
messageHash = name + ':' + market['id']
|
258
|
+
if self.myTrades is None:
|
259
|
+
limit = self.safe_integer(self.options, 'tradesLimit', 1000)
|
260
|
+
self.myTrades = ArrayCacheBySymbolById(limit)
|
261
|
+
tradesArray = self.myTrades
|
262
|
+
tradesArray.append(trade)
|
263
|
+
self.myTrades = tradesArray
|
264
|
+
# generic subscription
|
265
|
+
client.resolve(tradesArray, name)
|
266
|
+
# specific subscription
|
267
|
+
client.resolve(tradesArray, messageHash)
|
268
|
+
|
269
|
+
def handle_trades(self, client: Client, message, subscription):
|
270
|
+
#
|
271
|
+
# initial snapshot
|
101
272
|
#
|
102
|
-
#
|
103
|
-
#
|
273
|
+
# [
|
274
|
+
# 188687, # channel id
|
275
|
+
# [
|
276
|
+
# [1128060675, 1654701572690, 0.00217533, 1815.3], # id, mts, amount, price
|
277
|
+
# [1128060665, 1654701551231, -0.00280472, 1814.1],
|
278
|
+
# [1128060664, 1654701550996, -0.00364444, 1814.1],
|
279
|
+
# [1128060656, 1654701527730, -0.00265203, 1814.2],
|
280
|
+
# [1128060647, 1654701505193, 0.00262395, 1815.2],
|
281
|
+
# [1128060642, 1654701484656, -0.13411443, 1816],
|
282
|
+
# [1128060641, 1654701484656, -0.00088557, 1816],
|
283
|
+
# [1128060639, 1654701478326, -0.002, 1816],
|
284
|
+
# ]
|
285
|
+
# ]
|
286
|
+
# update
|
104
287
|
#
|
105
|
-
#
|
288
|
+
# [
|
289
|
+
# 360141,
|
290
|
+
# "te",
|
291
|
+
# [
|
292
|
+
# 1128060969, # id
|
293
|
+
# 1654702500098, # mts
|
294
|
+
# 0.00325131, # amount positive buy, negative sell
|
295
|
+
# 1818.5, # price
|
296
|
+
# ],
|
297
|
+
# ]
|
106
298
|
#
|
107
|
-
# # channel id, update type, seq, trade id, time, price, amount
|
108
|
-
# [2, "tu", "28462857-BTCUSD", 413357662, 1580565041, 9374.9, 0.005]
|
109
299
|
#
|
110
300
|
channel = self.safe_value(subscription, 'channel')
|
111
|
-
marketId = self.safe_string(subscription, '
|
301
|
+
marketId = self.safe_string(subscription, 'symbol')
|
302
|
+
market = self.safe_market(marketId)
|
112
303
|
messageHash = channel + ':' + marketId
|
113
304
|
tradesLimit = self.safe_integer(self.options, 'tradesLimit', 1000)
|
114
|
-
market = self.safe_market(marketId)
|
115
305
|
symbol = market['symbol']
|
116
|
-
data = self.safe_value(message, 1)
|
117
306
|
stored = self.safe_value(self.trades, symbol)
|
118
307
|
if stored is None:
|
119
308
|
stored = ArrayCache(tradesLimit)
|
120
309
|
self.trades[symbol] = stored
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
310
|
+
messageLength = len(message)
|
311
|
+
if messageLength == 2:
|
312
|
+
# initial snapshot
|
313
|
+
trades = self.safe_list(message, 1, [])
|
314
|
+
# needs to be reversed to make chronological order
|
315
|
+
length = len(trades)
|
316
|
+
for i in range(0, length):
|
317
|
+
index = length - i - 1
|
318
|
+
parsed = self.parse_ws_trade(trades[index], market)
|
319
|
+
stored.append(parsed)
|
125
320
|
else:
|
126
|
-
|
127
|
-
|
321
|
+
# update
|
322
|
+
type = self.safe_string(message, 1)
|
323
|
+
if type == 'tu':
|
324
|
+
# don't resolve for a duplicate update
|
325
|
+
# since te and tu updates are duplicated on the public stream
|
128
326
|
return
|
129
|
-
trade = self.
|
130
|
-
|
327
|
+
trade = self.safe_value(message, 2, [])
|
328
|
+
parsed = self.parse_ws_trade(trade, market)
|
329
|
+
stored.append(parsed)
|
131
330
|
client.resolve(stored, messageHash)
|
132
331
|
|
133
|
-
def
|
134
|
-
#
|
135
|
-
# snapshot trade
|
332
|
+
def parse_ws_trade(self, trade, market=None):
|
136
333
|
#
|
137
|
-
#
|
138
|
-
#
|
334
|
+
# [
|
335
|
+
# 1128060969, # id
|
336
|
+
# 1654702500098, # mts
|
337
|
+
# 0.00325131, # amount positive buy, negative sell
|
338
|
+
# 1818.5, # price
|
339
|
+
# ]
|
139
340
|
#
|
140
|
-
#
|
341
|
+
# trade execution
|
141
342
|
#
|
142
|
-
#
|
143
|
-
#
|
343
|
+
# [
|
344
|
+
# 1133411090, # id
|
345
|
+
# "tLTCUST", # symbol
|
346
|
+
# 1655110144598, # create ms
|
347
|
+
# 97084883506, # order id
|
348
|
+
# 0.1, # amount
|
349
|
+
# 42.821, # price
|
350
|
+
# "EXCHANGE MARKET", # order type
|
351
|
+
# 42.799, # order price
|
352
|
+
# -1, # maker
|
353
|
+
# null, # fee
|
354
|
+
# null, # fee currency
|
355
|
+
# 1655110144596 # cid
|
356
|
+
# ]
|
144
357
|
#
|
145
|
-
#
|
358
|
+
# trade update
|
146
359
|
#
|
147
|
-
#
|
148
|
-
#
|
360
|
+
# [
|
361
|
+
# 1133411090,
|
362
|
+
# "tLTCUST",
|
363
|
+
# 1655110144598,
|
364
|
+
# 97084883506,
|
365
|
+
# 0.1,
|
366
|
+
# 42.821,
|
367
|
+
# "EXCHANGE MARKET",
|
368
|
+
# 42.799,
|
369
|
+
# -1,
|
370
|
+
# -0.0002,
|
371
|
+
# "LTC",
|
372
|
+
# 1655110144596
|
373
|
+
# ]
|
149
374
|
#
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
if
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
375
|
+
numFields = len(trade)
|
376
|
+
isPublic = numFields <= 8
|
377
|
+
marketId = self.safe_string(trade, 1) if (not isPublic) else None
|
378
|
+
market = self.safe_market(marketId, market)
|
379
|
+
createdKey = 1 if isPublic else 2
|
380
|
+
priceKey = 3 if isPublic else 5
|
381
|
+
amountKey = 2 if isPublic else 4
|
382
|
+
marketId = market['id']
|
383
|
+
type = self.safe_string(trade, 6)
|
384
|
+
if type is not None:
|
385
|
+
if type.find('LIMIT') > -1:
|
386
|
+
type = 'limit'
|
387
|
+
elif type.find('MARKET') > -1:
|
388
|
+
type = 'market'
|
389
|
+
orderId = self.safe_string(trade, 3) if (not isPublic) else None
|
390
|
+
id = self.safe_string(trade, 0)
|
391
|
+
timestamp = self.safe_integer(trade, createdKey)
|
392
|
+
price = self.safe_string(trade, priceKey)
|
393
|
+
amountString = self.safe_string(trade, amountKey)
|
394
|
+
amount = self.parse_number(Precise.string_abs(amountString))
|
160
395
|
side = None
|
161
396
|
if amount is not None:
|
162
|
-
side = 'buy' if Precise.string_gt(
|
163
|
-
amount = Precise.string_abs(amount)
|
164
|
-
seq = self.safe_string(trade, 2)
|
165
|
-
parts = seq.split('-')
|
166
|
-
marketId = self.safe_string(parts, 1)
|
167
|
-
if marketId is not None:
|
168
|
-
marketId = marketId.replace('t', '')
|
397
|
+
side = 'buy' if Precise.string_gt(amountString, '0') else 'sell'
|
169
398
|
symbol = self.safe_symbol(marketId, market)
|
399
|
+
feeValue = self.safe_string(trade, 9)
|
400
|
+
fee = None
|
401
|
+
if feeValue is not None:
|
402
|
+
currencyId = self.safe_string(trade, 10)
|
403
|
+
code = self.safe_currency_code(currencyId)
|
404
|
+
fee = {
|
405
|
+
'cost': feeValue,
|
406
|
+
'currency': code,
|
407
|
+
}
|
408
|
+
maker = self.safe_integer(trade, 8)
|
170
409
|
takerOrMaker = None
|
171
|
-
|
410
|
+
if maker is not None:
|
411
|
+
takerOrMaker = 'taker' if (maker == -1) else 'maker'
|
172
412
|
return self.safe_trade({
|
173
413
|
'info': trade,
|
174
414
|
'timestamp': timestamp,
|
@@ -176,19 +416,20 @@ class bitfinex(ccxt.async_support.bitfinex):
|
|
176
416
|
'symbol': symbol,
|
177
417
|
'id': id,
|
178
418
|
'order': orderId,
|
179
|
-
'type':
|
419
|
+
'type': type,
|
180
420
|
'takerOrMaker': takerOrMaker,
|
181
421
|
'side': side,
|
182
422
|
'price': price,
|
183
423
|
'amount': amount,
|
184
424
|
'cost': None,
|
185
|
-
'fee':
|
186
|
-
})
|
425
|
+
'fee': fee,
|
426
|
+
}, market)
|
187
427
|
|
188
428
|
def handle_ticker(self, client: Client, message, subscription):
|
189
429
|
#
|
430
|
+
# [
|
431
|
+
# 340432, # channel ID
|
190
432
|
# [
|
191
|
-
# 2, # 0 CHANNEL_ID integer Channel ID
|
192
433
|
# 236.62, # 1 BID float Price of last highest bid
|
193
434
|
# 9.0029, # 2 BID_SIZE float Size of the last highest bid
|
194
435
|
# 236.88, # 3 ASK float Price of last lowest ask
|
@@ -200,40 +441,59 @@ class bitfinex(ccxt.async_support.bitfinex):
|
|
200
441
|
# 250.01, # 9 HIGH float Daily high
|
201
442
|
# 220.05, # 10 LOW float Daily low
|
202
443
|
# ]
|
444
|
+
# ]
|
203
445
|
#
|
204
|
-
|
446
|
+
ticker = self.safe_value(message, 1)
|
447
|
+
marketId = self.safe_string(subscription, 'symbol')
|
448
|
+
market = self.safe_market(marketId)
|
205
449
|
symbol = self.safe_symbol(marketId)
|
450
|
+
parsed = self.parse_ws_ticker(ticker, market)
|
206
451
|
channel = 'ticker'
|
207
452
|
messageHash = channel + ':' + marketId
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
453
|
+
self.tickers[symbol] = parsed
|
454
|
+
client.resolve(parsed, messageHash)
|
455
|
+
|
456
|
+
def parse_ws_ticker(self, ticker, market=None):
|
457
|
+
#
|
458
|
+
# [
|
459
|
+
# 236.62, # 1 BID float Price of last highest bid
|
460
|
+
# 9.0029, # 2 BID_SIZE float Size of the last highest bid
|
461
|
+
# 236.88, # 3 ASK float Price of last lowest ask
|
462
|
+
# 7.1138, # 4 ASK_SIZE float Size of the last lowest ask
|
463
|
+
# -1.02, # 5 DAILY_CHANGE float Amount that the last price has changed since yesterday
|
464
|
+
# 0, # 6 DAILY_CHANGE_PERC float Amount that the price has changed expressed in percentage terms
|
465
|
+
# 236.52, # 7 LAST_PRICE float Price of the last trade.
|
466
|
+
# 5191.36754297, # 8 VOLUME float Daily volume
|
467
|
+
# 250.01, # 9 HIGH float Daily high
|
468
|
+
# 220.05, # 10 LOW float Daily low
|
469
|
+
# ]
|
470
|
+
#
|
471
|
+
market = self.safe_market(None, market)
|
472
|
+
symbol = market['symbol']
|
473
|
+
last = self.safe_string(ticker, 6)
|
474
|
+
change = self.safe_string(ticker, 4)
|
475
|
+
return self.safe_ticker({
|
214
476
|
'symbol': symbol,
|
215
477
|
'timestamp': None,
|
216
478
|
'datetime': None,
|
217
|
-
'high': self.
|
218
|
-
'low': self.
|
219
|
-
'bid': self.
|
220
|
-
'bidVolume':
|
221
|
-
'ask': self.
|
222
|
-
'askVolume':
|
479
|
+
'high': self.safe_string(ticker, 8),
|
480
|
+
'low': self.safe_string(ticker, 9),
|
481
|
+
'bid': self.safe_string(ticker, 0),
|
482
|
+
'bidVolume': self.safe_string(ticker, 1),
|
483
|
+
'ask': self.safe_string(ticker, 2),
|
484
|
+
'askVolume': self.safe_string(ticker, 3),
|
223
485
|
'vwap': None,
|
224
|
-
'open':
|
225
|
-
'close':
|
226
|
-
'last':
|
486
|
+
'open': None,
|
487
|
+
'close': last,
|
488
|
+
'last': last,
|
227
489
|
'previousClose': None,
|
228
|
-
'change':
|
229
|
-
'percentage': self.
|
490
|
+
'change': change,
|
491
|
+
'percentage': self.safe_string(ticker, 5),
|
230
492
|
'average': None,
|
231
|
-
'baseVolume': self.
|
493
|
+
'baseVolume': self.safe_string(ticker, 7),
|
232
494
|
'quoteVolume': None,
|
233
|
-
'info':
|
234
|
-
}
|
235
|
-
self.tickers[symbol] = result
|
236
|
-
client.resolve(result, messageHash)
|
495
|
+
'info': ticker,
|
496
|
+
}, market)
|
237
497
|
|
238
498
|
async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
|
239
499
|
"""
|
@@ -249,14 +509,12 @@ class bitfinex(ccxt.async_support.bitfinex):
|
|
249
509
|
options = self.safe_value(self.options, 'watchOrderBook', {})
|
250
510
|
prec = self.safe_string(options, 'prec', 'P0')
|
251
511
|
freq = self.safe_string(options, 'freq', 'F0')
|
252
|
-
request = {
|
253
|
-
# "event": "subscribe", # added in subscribe()
|
254
|
-
# "channel": channel, # added in subscribe()
|
255
|
-
# "symbol": marketId, # added in subscribe()
|
512
|
+
request: dict = {
|
256
513
|
'prec': prec, # string, level of price aggregation, 'P0', 'P1', 'P2', 'P3', 'P4', default P0
|
257
514
|
'freq': freq, # string, frequency of updates 'F0' = realtime, 'F1' = 2 seconds, default is 'F0'
|
258
|
-
'len': limit, # string, number of price points, '25', '100', default = '25'
|
259
515
|
}
|
516
|
+
if limit is not None:
|
517
|
+
request['len'] = limit # string, number of price points, '25', '100', default = '25'
|
260
518
|
orderbook = await self.subscribe('book', symbol, self.deep_extend(request, params))
|
261
519
|
return orderbook.limit()
|
262
520
|
|
@@ -279,20 +537,22 @@ class bitfinex(ccxt.async_support.bitfinex):
|
|
279
537
|
# subsequent updates
|
280
538
|
#
|
281
539
|
# [
|
282
|
-
#
|
283
|
-
#
|
284
|
-
#
|
285
|
-
#
|
540
|
+
# 358169, # channel id
|
541
|
+
# [
|
542
|
+
# 1807.1, # price
|
543
|
+
# 0, # cound
|
544
|
+
# 1 # size
|
545
|
+
# ]
|
286
546
|
# ]
|
287
547
|
#
|
288
|
-
marketId = self.safe_string(subscription, '
|
548
|
+
marketId = self.safe_string(subscription, 'symbol')
|
289
549
|
symbol = self.safe_symbol(marketId)
|
290
550
|
channel = 'book'
|
291
551
|
messageHash = channel + ':' + marketId
|
292
552
|
prec = self.safe_string(subscription, 'prec', 'P0')
|
293
553
|
isRaw = (prec == 'R0')
|
294
554
|
# if it is an initial snapshot
|
295
|
-
if
|
555
|
+
if not (symbol in self.orderbooks):
|
296
556
|
limit = self.safe_integer(subscription, 'len')
|
297
557
|
if isRaw:
|
298
558
|
# raw order books
|
@@ -305,57 +565,211 @@ class bitfinex(ccxt.async_support.bitfinex):
|
|
305
565
|
deltas = message[1]
|
306
566
|
for i in range(0, len(deltas)):
|
307
567
|
delta = deltas[i]
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
size = -delta2Value if (delta2Value < 0) else delta2Value
|
312
|
-
side = 'asks' if (delta2Value < 0) else 'bids'
|
568
|
+
delta2 = delta[2]
|
569
|
+
size = -delta2 if (delta2 < 0) else delta2
|
570
|
+
side = 'asks' if (delta2 < 0) else 'bids'
|
313
571
|
bookside = orderbook[side]
|
314
|
-
|
572
|
+
idString = self.safe_string(delta, 0)
|
573
|
+
price = self.safe_float(delta, 1)
|
574
|
+
bookside.storeArray([price, size, idString])
|
315
575
|
else:
|
316
576
|
deltas = message[1]
|
317
577
|
for i in range(0, len(deltas)):
|
318
578
|
delta = deltas[i]
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
579
|
+
amount = self.safe_number(delta, 2)
|
580
|
+
counter = self.safe_number(delta, 1)
|
581
|
+
price = self.safe_number(delta, 0)
|
582
|
+
size = -amount if (amount < 0) else amount
|
583
|
+
side = 'asks' if (amount < 0) else 'bids'
|
584
|
+
bookside = orderbook[side]
|
585
|
+
bookside.storeArray([price, size, counter])
|
586
|
+
orderbook['symbol'] = symbol
|
324
587
|
client.resolve(orderbook, messageHash)
|
325
588
|
else:
|
326
589
|
orderbook = self.orderbooks[symbol]
|
590
|
+
deltas = message[1]
|
591
|
+
orderbookItem = self.orderbooks[symbol]
|
327
592
|
if isRaw:
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
bookside = orderbook[side]
|
593
|
+
price = self.safe_string(deltas, 1)
|
594
|
+
deltas2 = deltas[2]
|
595
|
+
size = -deltas2 if (deltas2 < 0) else deltas2
|
596
|
+
side = 'asks' if (deltas2 < 0) else 'bids'
|
597
|
+
bookside = orderbookItem[side]
|
334
598
|
# price = 0 means that you have to remove the order from your book
|
335
599
|
amount = size if Precise.string_gt(price, '0') else '0'
|
336
|
-
|
600
|
+
idString = self.safe_string(deltas, 0)
|
601
|
+
bookside.storeArray([self.parse_number(price), self.parse_number(amount), idString])
|
337
602
|
else:
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
603
|
+
amount = self.safe_string(deltas, 2)
|
604
|
+
counter = self.safe_string(deltas, 1)
|
605
|
+
price = self.safe_string(deltas, 0)
|
606
|
+
size = Precise.string_neg(amount) if Precise.string_lt(amount, '0') else amount
|
607
|
+
side = 'asks' if Precise.string_lt(amount, '0') else 'bids'
|
608
|
+
bookside = orderbookItem[side]
|
609
|
+
bookside.storeArray([self.parse_number(price), self.parse_number(size), self.parse_number(counter)])
|
343
610
|
client.resolve(orderbook, messageHash)
|
344
611
|
|
345
|
-
def
|
612
|
+
def handle_checksum(self, client: Client, message, subscription):
|
613
|
+
#
|
614
|
+
# [173904, "cs", -890884919]
|
615
|
+
#
|
616
|
+
marketId = self.safe_string(subscription, 'symbol')
|
617
|
+
symbol = self.safe_symbol(marketId)
|
618
|
+
channel = 'book'
|
619
|
+
messageHash = channel + ':' + marketId
|
620
|
+
book = self.safe_value(self.orderbooks, symbol)
|
621
|
+
if book is None:
|
622
|
+
return
|
623
|
+
depth = 25 # covers the first 25 bids and asks
|
624
|
+
stringArray = []
|
625
|
+
bids = book['bids']
|
626
|
+
asks = book['asks']
|
627
|
+
prec = self.safe_string(subscription, 'prec', 'P0')
|
628
|
+
isRaw = (prec == 'R0')
|
629
|
+
idToCheck = 2 if isRaw else 0
|
630
|
+
# pepperoni pizza from bitfinex
|
631
|
+
for i in range(0, depth):
|
632
|
+
bid = self.safe_value(bids, i)
|
633
|
+
ask = self.safe_value(asks, i)
|
634
|
+
if bid is not None:
|
635
|
+
stringArray.append(self.number_to_string(bids[i][idToCheck]))
|
636
|
+
stringArray.append(self.number_to_string(bids[i][1]))
|
637
|
+
if ask is not None:
|
638
|
+
stringArray.append(self.number_to_string(asks[i][idToCheck]))
|
639
|
+
aski1 = asks[i][1]
|
640
|
+
stringArray.append(self.number_to_string(-aski1))
|
641
|
+
payload = ':'.join(stringArray)
|
642
|
+
localChecksum = self.crc32(payload, True)
|
643
|
+
responseChecksum = self.safe_integer(message, 2)
|
644
|
+
if responseChecksum != localChecksum:
|
645
|
+
del client.subscriptions[messageHash]
|
646
|
+
del self.orderbooks[symbol]
|
647
|
+
checksum = self.handle_option('watchOrderBook', 'checksum', True)
|
648
|
+
if checksum:
|
649
|
+
error = ChecksumError(self.id + ' ' + self.orderbook_checksum_message(symbol))
|
650
|
+
client.reject(error, messageHash)
|
651
|
+
|
652
|
+
async def watch_balance(self, params={}) -> Balances:
|
653
|
+
"""
|
654
|
+
watch balance and get the amount of funds available for trading or funds locked in orders
|
655
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
656
|
+
:param str [params.type]: spot or contract if not provided self.options['defaultType'] is used
|
657
|
+
:returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
|
658
|
+
"""
|
659
|
+
await self.load_markets()
|
660
|
+
balanceType = self.safe_string(params, 'wallet', 'exchange') # exchange, margin
|
661
|
+
params = self.omit(params, 'wallet')
|
662
|
+
messageHash = 'balance:' + balanceType
|
663
|
+
return await self.subscribe_private(messageHash)
|
664
|
+
|
665
|
+
def handle_balance(self, client: Client, message, subscription):
|
346
666
|
#
|
347
|
-
#
|
667
|
+
# snapshot(exchange + margin together)
|
668
|
+
# [
|
669
|
+
# 0,
|
670
|
+
# "ws",
|
671
|
+
# [
|
672
|
+
# [
|
673
|
+
# "exchange",
|
674
|
+
# "LTC",
|
675
|
+
# 0.05479727,
|
676
|
+
# 0,
|
677
|
+
# null,
|
678
|
+
# "Trading fees for 0.05 LTC(LTCUST) @ 51.872 on BFX(0.2%)",
|
679
|
+
# null,
|
680
|
+
# ]
|
681
|
+
# [
|
682
|
+
# "margin",
|
683
|
+
# "USTF0",
|
684
|
+
# 11.960650700086292,
|
685
|
+
# 0,
|
686
|
+
# null,
|
687
|
+
# "Trading fees for 0.1 LTCF0(LTCF0:USTF0) @ 51.844 on BFX(0.065%)",
|
688
|
+
# null,
|
689
|
+
# ],
|
690
|
+
# ],
|
691
|
+
# ]
|
348
692
|
#
|
349
|
-
#
|
693
|
+
# spot
|
694
|
+
# [
|
695
|
+
# 0,
|
696
|
+
# "wu",
|
697
|
+
# [
|
698
|
+
# "exchange",
|
699
|
+
# "LTC", # currency
|
700
|
+
# 0.06729727, # wallet balance
|
701
|
+
# 0, # unsettled balance
|
702
|
+
# 0.06729727, # available balance might be null
|
703
|
+
# "Exchange 0.4 LTC for UST @ 65.075",
|
704
|
+
# {
|
705
|
+
# "reason": "TRADE",
|
706
|
+
# "order_id": 96596397973,
|
707
|
+
# "order_id_oppo": 96596632735,
|
708
|
+
# "trade_price": "65.075",
|
709
|
+
# "trade_amount": "-0.4",
|
710
|
+
# "order_cid": 1654636218766,
|
711
|
+
# "order_gid": null
|
712
|
+
# }
|
713
|
+
# ]
|
714
|
+
# ]
|
350
715
|
#
|
351
|
-
|
352
|
-
|
716
|
+
# margin
|
717
|
+
#
|
718
|
+
# [
|
719
|
+
# "margin",
|
720
|
+
# "USTF0",
|
721
|
+
# 11.960650700086292, # total
|
722
|
+
# 0,
|
723
|
+
# 6.776250700086292, # available
|
724
|
+
# "Trading fees for 0.1 LTCF0(LTCF0:USTF0) @ 51.844 on BFX(0.065%)",
|
725
|
+
# null
|
726
|
+
# ]
|
727
|
+
#
|
728
|
+
updateType = self.safe_value(message, 1)
|
729
|
+
data = None
|
730
|
+
if updateType == 'ws':
|
731
|
+
data = self.safe_value(message, 2)
|
732
|
+
else:
|
733
|
+
data = [self.safe_value(message, 2)]
|
734
|
+
updatedTypes: dict = {}
|
735
|
+
for i in range(0, len(data)):
|
736
|
+
rawBalance = data[i]
|
737
|
+
currencyId = self.safe_string(rawBalance, 1)
|
738
|
+
code = self.safe_currency_code(currencyId)
|
739
|
+
balance = self.parse_ws_balance(rawBalance)
|
740
|
+
balanceType = self.safe_string(rawBalance, 0)
|
741
|
+
oldBalance = self.safe_value(self.balance, balanceType, {})
|
742
|
+
oldBalance[code] = balance
|
743
|
+
oldBalance['info'] = message
|
744
|
+
self.balance[balanceType] = self.safe_balance(oldBalance)
|
745
|
+
updatedTypes[balanceType] = True
|
746
|
+
updatesKeys = list(updatedTypes.keys())
|
747
|
+
for i in range(0, len(updatesKeys)):
|
748
|
+
type = updatesKeys[i]
|
749
|
+
messageHash = 'balance:' + type
|
750
|
+
client.resolve(self.balance[type], messageHash)
|
353
751
|
|
354
|
-
def
|
752
|
+
def parse_ws_balance(self, balance):
|
355
753
|
#
|
356
|
-
#
|
357
|
-
#
|
358
|
-
#
|
754
|
+
# [
|
755
|
+
# "exchange",
|
756
|
+
# "LTC",
|
757
|
+
# 0.05479727, # balance
|
758
|
+
# 0,
|
759
|
+
# null, # available null if not calculated yet
|
760
|
+
# "Trading fees for 0.05 LTC(LTCUST) @ 51.872 on BFX(0.2%)",
|
761
|
+
# null,
|
762
|
+
# ]
|
763
|
+
#
|
764
|
+
totalBalance = self.safe_string(balance, 2)
|
765
|
+
availableBalance = self.safe_string(balance, 4)
|
766
|
+
account = self.account()
|
767
|
+
if availableBalance is not None:
|
768
|
+
account['free'] = availableBalance
|
769
|
+
account['total'] = totalBalance
|
770
|
+
return account
|
771
|
+
|
772
|
+
def handle_system_status(self, client: Client, message):
|
359
773
|
#
|
360
774
|
# {
|
361
775
|
# "event": "info",
|
@@ -386,46 +800,38 @@ class bitfinex(ccxt.async_support.bitfinex):
|
|
386
800
|
async def authenticate(self, params={}):
|
387
801
|
url = self.urls['api']['ws']['private']
|
388
802
|
client = self.client(url)
|
389
|
-
|
390
|
-
|
391
|
-
authenticated = self.safe_value(client.subscriptions,
|
803
|
+
messageHash = 'authenticated'
|
804
|
+
future = client.future(messageHash)
|
805
|
+
authenticated = self.safe_value(client.subscriptions, messageHash)
|
392
806
|
if authenticated is None:
|
393
807
|
nonce = self.milliseconds()
|
394
808
|
payload = 'AUTH' + str(nonce)
|
395
809
|
signature = self.hmac(self.encode(payload), self.encode(self.secret), hashlib.sha384, 'hex')
|
396
|
-
|
810
|
+
event = 'auth'
|
811
|
+
request: dict = {
|
397
812
|
'apiKey': self.apiKey,
|
398
813
|
'authSig': signature,
|
399
814
|
'authNonce': nonce,
|
400
815
|
'authPayload': payload,
|
401
|
-
'event':
|
402
|
-
'filter': [
|
403
|
-
'trading',
|
404
|
-
'wallet',
|
405
|
-
],
|
816
|
+
'event': event,
|
406
817
|
}
|
407
|
-
self.
|
818
|
+
message = self.extend(request, params)
|
819
|
+
self.watch(url, messageHash, message, messageHash)
|
408
820
|
return await future
|
409
821
|
|
410
822
|
def handle_authentication_message(self, client: Client, message):
|
823
|
+
messageHash = 'authenticated'
|
411
824
|
status = self.safe_string(message, 'status')
|
412
825
|
if status == 'OK':
|
413
826
|
# we resolve the future here permanently so authentication only happens once
|
414
|
-
future = self.safe_value(client.futures,
|
827
|
+
future = self.safe_value(client.futures, messageHash)
|
415
828
|
future.resolve(True)
|
416
829
|
else:
|
417
830
|
error = AuthenticationError(self.json(message))
|
418
|
-
client.reject(error,
|
831
|
+
client.reject(error, messageHash)
|
419
832
|
# allows further authentication attempts
|
420
|
-
|
421
|
-
|
422
|
-
del client.subscriptions[method]
|
423
|
-
|
424
|
-
async def watch_order(self, id, symbol: Str = None, params={}):
|
425
|
-
await self.load_markets()
|
426
|
-
url = self.urls['api']['ws']['private']
|
427
|
-
await self.authenticate()
|
428
|
-
return await self.watch(url, id, None, 1)
|
833
|
+
if messageHash in client.subscriptions:
|
834
|
+
del client.subscriptions[messageHash]
|
429
835
|
|
430
836
|
async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
431
837
|
"""
|
@@ -437,115 +843,161 @@ class bitfinex(ccxt.async_support.bitfinex):
|
|
437
843
|
:returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
438
844
|
"""
|
439
845
|
await self.load_markets()
|
440
|
-
|
846
|
+
messageHash = 'orders'
|
441
847
|
if symbol is not None:
|
442
|
-
|
443
|
-
|
444
|
-
orders = await self.
|
848
|
+
market = self.market(symbol)
|
849
|
+
messageHash += ':' + market['id']
|
850
|
+
orders = await self.subscribe_private(messageHash)
|
445
851
|
if self.newUpdates:
|
446
852
|
limit = orders.getLimit(symbol, limit)
|
447
853
|
return self.filter_by_symbol_since_limit(orders, symbol, since, limit, True)
|
448
854
|
|
449
855
|
def handle_orders(self, client: Client, message, subscription):
|
450
856
|
#
|
451
|
-
# order
|
452
|
-
#
|
453
|
-
#
|
454
|
-
#
|
455
|
-
#
|
456
|
-
#
|
457
|
-
#
|
458
|
-
#
|
459
|
-
#
|
460
|
-
#
|
461
|
-
#
|
462
|
-
#
|
463
|
-
#
|
464
|
-
#
|
465
|
-
#
|
466
|
-
#
|
467
|
-
#
|
468
|
-
#
|
469
|
-
#
|
470
|
-
#
|
471
|
-
#
|
472
|
-
#
|
473
|
-
#
|
474
|
-
#
|
475
|
-
#
|
476
|
-
#
|
477
|
-
#
|
478
|
-
#
|
479
|
-
#
|
480
|
-
#
|
481
|
-
#
|
482
|
-
#
|
483
|
-
#
|
484
|
-
#
|
485
|
-
#
|
486
|
-
#
|
487
|
-
#
|
488
|
-
#
|
489
|
-
# 0,
|
490
|
-
# 0,
|
491
|
-
# 0,
|
492
|
-
# ]
|
493
|
-
# ]
|
857
|
+
# limit order
|
858
|
+
# [
|
859
|
+
# 0,
|
860
|
+
# "on", # ou or oc
|
861
|
+
# [
|
862
|
+
# 96923856256, # order id
|
863
|
+
# null, # gid
|
864
|
+
# 1655029337026, # cid
|
865
|
+
# "tLTCUST", # symbol
|
866
|
+
# 1655029337027, # created timestamp
|
867
|
+
# 1655029337029, # updated timestamp
|
868
|
+
# 0.1, # amount
|
869
|
+
# 0.1, # amount_orig
|
870
|
+
# "EXCHANGE LIMIT", # order type
|
871
|
+
# null, # type_prev
|
872
|
+
# null, # mts_tif
|
873
|
+
# null, # placeholder
|
874
|
+
# 0, # flags
|
875
|
+
# "ACTIVE", # status
|
876
|
+
# null,
|
877
|
+
# null,
|
878
|
+
# 30, # price
|
879
|
+
# 0, # price average
|
880
|
+
# 0, # price_trailling
|
881
|
+
# 0, # price_aux_limit
|
882
|
+
# null,
|
883
|
+
# null,
|
884
|
+
# null,
|
885
|
+
# 0, # notify
|
886
|
+
# 0,
|
887
|
+
# null,
|
888
|
+
# null,
|
889
|
+
# null,
|
890
|
+
# "BFX",
|
891
|
+
# null,
|
892
|
+
# null,
|
893
|
+
# ]
|
894
|
+
# ]
|
494
895
|
#
|
495
896
|
data = self.safe_value(message, 2, [])
|
496
897
|
messageType = self.safe_string(message, 1)
|
898
|
+
if self.orders is None:
|
899
|
+
limit = self.safe_integer(self.options, 'ordersLimit', 1000)
|
900
|
+
self.orders = ArrayCacheBySymbolById(limit)
|
901
|
+
orders = self.orders
|
902
|
+
symbolIds: dict = {}
|
497
903
|
if messageType == 'os':
|
904
|
+
snapshotLength = len(data)
|
905
|
+
if snapshotLength == 0:
|
906
|
+
return
|
498
907
|
for i in range(0, len(data)):
|
499
908
|
value = data[i]
|
500
|
-
self.
|
909
|
+
parsed = self.parse_ws_order(value)
|
910
|
+
symbol = parsed['symbol']
|
911
|
+
symbolIds[symbol] = True
|
912
|
+
orders.append(parsed)
|
501
913
|
else:
|
502
|
-
self.
|
503
|
-
|
504
|
-
|
914
|
+
parsed = self.parse_ws_order(data)
|
915
|
+
orders.append(parsed)
|
916
|
+
symbol = parsed['symbol']
|
917
|
+
symbolIds[symbol] = True
|
918
|
+
name = 'orders'
|
919
|
+
client.resolve(self.orders, name)
|
920
|
+
keys = list(symbolIds.keys())
|
921
|
+
for i in range(0, len(keys)):
|
922
|
+
symbol = keys[i]
|
923
|
+
market = self.market(symbol)
|
924
|
+
messageHash = name + ':' + market['id']
|
925
|
+
client.resolve(self.orders, messageHash)
|
505
926
|
|
506
927
|
def parse_ws_order_status(self, status):
|
507
|
-
statuses = {
|
928
|
+
statuses: dict = {
|
508
929
|
'ACTIVE': 'open',
|
509
930
|
'CANCELED': 'canceled',
|
931
|
+
'EXECUTED': 'closed',
|
932
|
+
'PARTIALLY': 'open',
|
510
933
|
}
|
511
934
|
return self.safe_string(statuses, status, status)
|
512
935
|
|
513
|
-
def
|
514
|
-
#
|
515
|
-
#
|
516
|
-
#
|
517
|
-
#
|
518
|
-
#
|
519
|
-
#
|
520
|
-
#
|
521
|
-
#
|
522
|
-
#
|
523
|
-
#
|
524
|
-
#
|
525
|
-
#
|
936
|
+
def parse_ws_order(self, order, market=None):
|
937
|
+
#
|
938
|
+
# [
|
939
|
+
# 97084883506, # order id
|
940
|
+
# null,
|
941
|
+
# 1655110144596, # clientOrderId
|
942
|
+
# "tLTCUST", # symbol
|
943
|
+
# 1655110144596, # created timestamp
|
944
|
+
# 1655110144598, # updated timestamp
|
945
|
+
# 0, # amount
|
946
|
+
# 0.1, # amount_orig negative if sell order
|
947
|
+
# "EXCHANGE MARKET", # type
|
948
|
+
# null,
|
949
|
+
# null,
|
950
|
+
# null,
|
951
|
+
# 0,
|
952
|
+
# "EXECUTED @ 42.821(0.1)", # status
|
953
|
+
# null,
|
954
|
+
# null,
|
955
|
+
# 42.799, # price
|
956
|
+
# 42.821, # price average
|
957
|
+
# 0, # price trailling
|
958
|
+
# 0, # price_aux_limit
|
959
|
+
# null,
|
960
|
+
# null,
|
961
|
+
# null,
|
962
|
+
# 0,
|
963
|
+
# 0,
|
964
|
+
# null,
|
965
|
+
# null,
|
966
|
+
# null,
|
967
|
+
# "BFX",
|
968
|
+
# null,
|
969
|
+
# null,
|
970
|
+
# {}
|
971
|
+
# ]
|
972
|
+
#
|
526
973
|
id = self.safe_string(order, 0)
|
527
|
-
|
974
|
+
clientOrderId = self.safe_string(order, 1)
|
975
|
+
marketId = self.safe_string(order, 3)
|
528
976
|
symbol = self.safe_symbol(marketId)
|
529
|
-
|
530
|
-
|
977
|
+
market = self.safe_market(symbol)
|
978
|
+
amount = self.safe_string(order, 7)
|
531
979
|
side = 'buy'
|
532
980
|
if Precise.string_lt(amount, '0'):
|
533
981
|
amount = Precise.string_abs(amount)
|
534
|
-
remaining = Precise.string_abs(remaining)
|
535
982
|
side = 'sell'
|
536
|
-
|
983
|
+
remaining = Precise.string_abs(self.safe_string(order, 6))
|
984
|
+
type = self.safe_string(order, 8)
|
537
985
|
if type.find('LIMIT') > -1:
|
538
986
|
type = 'limit'
|
539
987
|
elif type.find('MARKET') > -1:
|
540
988
|
type = 'market'
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
989
|
+
rawState = self.safe_string(order, 13)
|
990
|
+
stateParts = rawState.split(' ')
|
991
|
+
trimmedStatus = self.safe_string(stateParts, 0)
|
992
|
+
status = self.parse_ws_order_status(trimmedStatus)
|
993
|
+
price = self.safe_string(order, 16)
|
994
|
+
timestamp = self.safe_integer_2(order, 5, 4)
|
995
|
+
average = self.safe_string(order, 17)
|
996
|
+
stopPrice = self.omit_zero(self.safe_string(order, 18))
|
997
|
+
return self.safe_order({
|
546
998
|
'info': order,
|
547
999
|
'id': id,
|
548
|
-
'clientOrderId':
|
1000
|
+
'clientOrderId': clientOrderId,
|
549
1001
|
'timestamp': timestamp,
|
550
1002
|
'datetime': self.iso8601(timestamp),
|
551
1003
|
'lastTradeTimestamp': None,
|
@@ -553,9 +1005,9 @@ class bitfinex(ccxt.async_support.bitfinex):
|
|
553
1005
|
'type': type,
|
554
1006
|
'side': side,
|
555
1007
|
'price': price,
|
556
|
-
'stopPrice':
|
557
|
-
'triggerPrice':
|
558
|
-
'average':
|
1008
|
+
'stopPrice': stopPrice,
|
1009
|
+
'triggerPrice': stopPrice,
|
1010
|
+
'average': average,
|
559
1011
|
'amount': amount,
|
560
1012
|
'remaining': remaining,
|
561
1013
|
'filled': None,
|
@@ -563,56 +1015,69 @@ class bitfinex(ccxt.async_support.bitfinex):
|
|
563
1015
|
'fee': None,
|
564
1016
|
'cost': None,
|
565
1017
|
'trades': None,
|
566
|
-
})
|
567
|
-
if self.orders is None:
|
568
|
-
limit = self.safe_integer(self.options, 'ordersLimit', 1000)
|
569
|
-
self.orders = ArrayCacheBySymbolById(limit)
|
570
|
-
orders = self.orders
|
571
|
-
orders.append(parsed)
|
572
|
-
client.resolve(parsed, id)
|
573
|
-
return parsed
|
1018
|
+
}, market)
|
574
1019
|
|
575
1020
|
def handle_message(self, client: Client, message):
|
1021
|
+
channelId = self.safe_string(message, 0)
|
1022
|
+
#
|
1023
|
+
# [
|
1024
|
+
# 1231,
|
1025
|
+
# "hb",
|
1026
|
+
# ]
|
1027
|
+
#
|
1028
|
+
# auth message
|
1029
|
+
# {
|
1030
|
+
# "event": "auth",
|
1031
|
+
# "status": "OK",
|
1032
|
+
# "chanId": 0,
|
1033
|
+
# "userId": 3159883,
|
1034
|
+
# "auth_id": "ac7108e7-2f26-424d-9982-c24700dc02ca",
|
1035
|
+
# "caps": {
|
1036
|
+
# "orders": {read: 1, write: 1},
|
1037
|
+
# "account": {read: 1, write: 1},
|
1038
|
+
# "funding": {read: 1, write: 1},
|
1039
|
+
# "history": {read: 1, write: 0},
|
1040
|
+
# "wallets": {read: 1, write: 1},
|
1041
|
+
# "withdraw": {read: 0, write: 1},
|
1042
|
+
# "positions": {read: 1, write: 1},
|
1043
|
+
# "ui_withdraw": {read: 0, write: 0}
|
1044
|
+
# }
|
1045
|
+
# }
|
1046
|
+
#
|
576
1047
|
if isinstance(message, list):
|
577
|
-
channelId = self.safe_string(message, 0)
|
578
|
-
#
|
579
|
-
# [
|
580
|
-
# 1231,
|
581
|
-
# "hb",
|
582
|
-
# ]
|
583
|
-
#
|
584
1048
|
if message[1] == 'hb':
|
585
1049
|
return # skip heartbeats within subscription channels for now
|
586
1050
|
subscription = self.safe_value(client.subscriptions, channelId, {})
|
587
1051
|
channel = self.safe_string(subscription, 'channel')
|
588
1052
|
name = self.safe_string(message, 1)
|
589
|
-
|
1053
|
+
publicMethods: dict = {
|
590
1054
|
'book': self.handle_order_book,
|
591
|
-
|
1055
|
+
'cs': self.handle_checksum,
|
1056
|
+
'candles': self.handle_ohlcv,
|
592
1057
|
'ticker': self.handle_ticker,
|
593
1058
|
'trades': self.handle_trades,
|
1059
|
+
}
|
1060
|
+
privateMethods: dict = {
|
594
1061
|
'os': self.handle_orders,
|
1062
|
+
'ou': self.handle_orders,
|
595
1063
|
'on': self.handle_orders,
|
596
1064
|
'oc': self.handle_orders,
|
1065
|
+
'wu': self.handle_balance,
|
1066
|
+
'ws': self.handle_balance,
|
1067
|
+
'tu': self.handle_my_trade,
|
597
1068
|
}
|
598
|
-
method =
|
1069
|
+
method = None
|
1070
|
+
if channelId == '0':
|
1071
|
+
method = self.safe_value(privateMethods, name)
|
1072
|
+
else:
|
1073
|
+
method = self.safe_value_2(publicMethods, name, channel)
|
599
1074
|
if method is not None:
|
600
1075
|
method(client, message, subscription)
|
601
1076
|
else:
|
602
|
-
# todo add bitfinex handleErrorMessage
|
603
|
-
#
|
604
|
-
# {
|
605
|
-
# "event": "info",
|
606
|
-
# "version": 2,
|
607
|
-
# "serverId": "e293377e-7bb7-427e-b28c-5db045b2c1d1",
|
608
|
-
# "platform": {status: 1}, # 1 for operative, 0 for maintenance
|
609
|
-
# }
|
610
|
-
#
|
611
1077
|
event = self.safe_string(message, 'event')
|
612
1078
|
if event is not None:
|
613
|
-
methods = {
|
1079
|
+
methods: dict = {
|
614
1080
|
'info': self.handle_system_status,
|
615
|
-
# 'book': 'handleOrderBook',
|
616
1081
|
'subscribed': self.handle_subscription_status,
|
617
1082
|
'auth': self.handle_authentication_message,
|
618
1083
|
}
|