kucoin-api 0.0.11__py3-none-any.whl → 0.0.12__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.
Potentially problematic release.
This version of kucoin-api might be problematic. Click here for more details.
- {kucoin_api-0.0.11.dist-info → kucoin_api-0.0.12.dist-info}/METADATA +33 -14
- kucoin_api-0.0.12.dist-info/RECORD +3 -0
- kucoin_api/__init__.py +0 -7
- kucoin_api/ccxt/__init__.py +0 -101
- kucoin_api/ccxt/abstract/kucoin.py +0 -224
- kucoin_api/ccxt/async_support/__init__.py +0 -80
- kucoin_api/ccxt/async_support/base/__init__.py +0 -1
- kucoin_api/ccxt/async_support/base/exchange.py +0 -2100
- kucoin_api/ccxt/async_support/base/throttler.py +0 -50
- kucoin_api/ccxt/async_support/base/ws/__init__.py +0 -38
- kucoin_api/ccxt/async_support/base/ws/aiohttp_client.py +0 -147
- kucoin_api/ccxt/async_support/base/ws/cache.py +0 -213
- kucoin_api/ccxt/async_support/base/ws/client.py +0 -214
- kucoin_api/ccxt/async_support/base/ws/fast_client.py +0 -97
- kucoin_api/ccxt/async_support/base/ws/functions.py +0 -59
- kucoin_api/ccxt/async_support/base/ws/future.py +0 -69
- kucoin_api/ccxt/async_support/base/ws/order_book.py +0 -78
- kucoin_api/ccxt/async_support/base/ws/order_book_side.py +0 -174
- kucoin_api/ccxt/async_support/kucoin.py +0 -4920
- kucoin_api/ccxt/base/__init__.py +0 -27
- kucoin_api/ccxt/base/decimal_to_precision.py +0 -174
- kucoin_api/ccxt/base/errors.py +0 -267
- kucoin_api/ccxt/base/exchange.py +0 -6770
- kucoin_api/ccxt/base/precise.py +0 -297
- kucoin_api/ccxt/base/types.py +0 -577
- kucoin_api/ccxt/kucoin.py +0 -4919
- kucoin_api/ccxt/pro/__init__.py +0 -21
- kucoin_api/ccxt/pro/kucoin.py +0 -1356
- kucoin_api/ccxt/static_dependencies/README.md +0 -1
- kucoin_api/ccxt/static_dependencies/__init__.py +0 -1
- kucoin_api/ccxt/static_dependencies/ecdsa/__init__.py +0 -14
- kucoin_api/ccxt/static_dependencies/ecdsa/_version.py +0 -520
- kucoin_api/ccxt/static_dependencies/ecdsa/curves.py +0 -56
- kucoin_api/ccxt/static_dependencies/ecdsa/der.py +0 -221
- kucoin_api/ccxt/static_dependencies/ecdsa/ecdsa.py +0 -310
- kucoin_api/ccxt/static_dependencies/ecdsa/ellipticcurve.py +0 -197
- kucoin_api/ccxt/static_dependencies/ecdsa/keys.py +0 -332
- kucoin_api/ccxt/static_dependencies/ecdsa/numbertheory.py +0 -531
- kucoin_api/ccxt/static_dependencies/ecdsa/rfc6979.py +0 -100
- kucoin_api/ccxt/static_dependencies/ecdsa/util.py +0 -266
- kucoin_api/ccxt/static_dependencies/ethereum/__init__.py +0 -7
- kucoin_api/ccxt/static_dependencies/ethereum/abi/__init__.py +0 -16
- kucoin_api/ccxt/static_dependencies/ethereum/abi/abi.py +0 -19
- kucoin_api/ccxt/static_dependencies/ethereum/abi/base.py +0 -152
- kucoin_api/ccxt/static_dependencies/ethereum/abi/codec.py +0 -217
- kucoin_api/ccxt/static_dependencies/ethereum/abi/constants.py +0 -3
- kucoin_api/ccxt/static_dependencies/ethereum/abi/decoding.py +0 -565
- kucoin_api/ccxt/static_dependencies/ethereum/abi/encoding.py +0 -720
- kucoin_api/ccxt/static_dependencies/ethereum/abi/exceptions.py +0 -139
- kucoin_api/ccxt/static_dependencies/ethereum/abi/grammar.py +0 -443
- kucoin_api/ccxt/static_dependencies/ethereum/abi/packed.py +0 -13
- kucoin_api/ccxt/static_dependencies/ethereum/abi/py.typed +0 -0
- kucoin_api/ccxt/static_dependencies/ethereum/abi/registry.py +0 -643
- kucoin_api/ccxt/static_dependencies/ethereum/abi/tools/__init__.py +0 -3
- kucoin_api/ccxt/static_dependencies/ethereum/abi/tools/_strategies.py +0 -230
- kucoin_api/ccxt/static_dependencies/ethereum/abi/utils/__init__.py +0 -0
- kucoin_api/ccxt/static_dependencies/ethereum/abi/utils/numeric.py +0 -83
- kucoin_api/ccxt/static_dependencies/ethereum/abi/utils/padding.py +0 -27
- kucoin_api/ccxt/static_dependencies/ethereum/abi/utils/string.py +0 -19
- kucoin_api/ccxt/static_dependencies/ethereum/account/__init__.py +0 -3
- kucoin_api/ccxt/static_dependencies/ethereum/account/encode_typed_data/__init__.py +0 -4
- kucoin_api/ccxt/static_dependencies/ethereum/account/encode_typed_data/encoding_and_hashing.py +0 -239
- kucoin_api/ccxt/static_dependencies/ethereum/account/encode_typed_data/helpers.py +0 -40
- kucoin_api/ccxt/static_dependencies/ethereum/account/messages.py +0 -263
- kucoin_api/ccxt/static_dependencies/ethereum/account/py.typed +0 -0
- kucoin_api/ccxt/static_dependencies/ethereum/hexbytes/__init__.py +0 -5
- kucoin_api/ccxt/static_dependencies/ethereum/hexbytes/_utils.py +0 -54
- kucoin_api/ccxt/static_dependencies/ethereum/hexbytes/main.py +0 -65
- kucoin_api/ccxt/static_dependencies/ethereum/hexbytes/py.typed +0 -0
- kucoin_api/ccxt/static_dependencies/ethereum/typing/__init__.py +0 -63
- kucoin_api/ccxt/static_dependencies/ethereum/typing/abi.py +0 -6
- kucoin_api/ccxt/static_dependencies/ethereum/typing/bls.py +0 -7
- kucoin_api/ccxt/static_dependencies/ethereum/typing/discovery.py +0 -5
- kucoin_api/ccxt/static_dependencies/ethereum/typing/encoding.py +0 -7
- kucoin_api/ccxt/static_dependencies/ethereum/typing/enums.py +0 -17
- kucoin_api/ccxt/static_dependencies/ethereum/typing/ethpm.py +0 -9
- kucoin_api/ccxt/static_dependencies/ethereum/typing/evm.py +0 -20
- kucoin_api/ccxt/static_dependencies/ethereum/typing/networks.py +0 -1122
- kucoin_api/ccxt/static_dependencies/ethereum/typing/py.typed +0 -0
- kucoin_api/ccxt/static_dependencies/ethereum/utils/__init__.py +0 -115
- kucoin_api/ccxt/static_dependencies/ethereum/utils/abi.py +0 -72
- kucoin_api/ccxt/static_dependencies/ethereum/utils/address.py +0 -171
- kucoin_api/ccxt/static_dependencies/ethereum/utils/applicators.py +0 -151
- kucoin_api/ccxt/static_dependencies/ethereum/utils/conversions.py +0 -190
- kucoin_api/ccxt/static_dependencies/ethereum/utils/currency.py +0 -107
- kucoin_api/ccxt/static_dependencies/ethereum/utils/curried/__init__.py +0 -269
- kucoin_api/ccxt/static_dependencies/ethereum/utils/debug.py +0 -20
- kucoin_api/ccxt/static_dependencies/ethereum/utils/decorators.py +0 -132
- kucoin_api/ccxt/static_dependencies/ethereum/utils/encoding.py +0 -6
- kucoin_api/ccxt/static_dependencies/ethereum/utils/exceptions.py +0 -4
- kucoin_api/ccxt/static_dependencies/ethereum/utils/functional.py +0 -75
- kucoin_api/ccxt/static_dependencies/ethereum/utils/hexadecimal.py +0 -74
- kucoin_api/ccxt/static_dependencies/ethereum/utils/humanize.py +0 -188
- kucoin_api/ccxt/static_dependencies/ethereum/utils/logging.py +0 -159
- kucoin_api/ccxt/static_dependencies/ethereum/utils/module_loading.py +0 -31
- kucoin_api/ccxt/static_dependencies/ethereum/utils/numeric.py +0 -43
- kucoin_api/ccxt/static_dependencies/ethereum/utils/py.typed +0 -0
- kucoin_api/ccxt/static_dependencies/ethereum/utils/toolz.py +0 -76
- kucoin_api/ccxt/static_dependencies/ethereum/utils/types.py +0 -54
- kucoin_api/ccxt/static_dependencies/ethereum/utils/typing/__init__.py +0 -18
- kucoin_api/ccxt/static_dependencies/ethereum/utils/typing/misc.py +0 -14
- kucoin_api/ccxt/static_dependencies/ethereum/utils/units.py +0 -31
- kucoin_api/ccxt/static_dependencies/keccak/__init__.py +0 -3
- kucoin_api/ccxt/static_dependencies/keccak/keccak.py +0 -197
- kucoin_api/ccxt/static_dependencies/lark/__init__.py +0 -38
- kucoin_api/ccxt/static_dependencies/lark/__pyinstaller/__init__.py +0 -6
- kucoin_api/ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +0 -14
- kucoin_api/ccxt/static_dependencies/lark/ast_utils.py +0 -59
- kucoin_api/ccxt/static_dependencies/lark/common.py +0 -86
- kucoin_api/ccxt/static_dependencies/lark/exceptions.py +0 -292
- kucoin_api/ccxt/static_dependencies/lark/grammar.py +0 -130
- kucoin_api/ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
- kucoin_api/ccxt/static_dependencies/lark/grammars/common.lark +0 -59
- kucoin_api/ccxt/static_dependencies/lark/grammars/lark.lark +0 -62
- kucoin_api/ccxt/static_dependencies/lark/grammars/python.lark +0 -302
- kucoin_api/ccxt/static_dependencies/lark/grammars/unicode.lark +0 -7
- kucoin_api/ccxt/static_dependencies/lark/indenter.py +0 -143
- kucoin_api/ccxt/static_dependencies/lark/lark.py +0 -658
- kucoin_api/ccxt/static_dependencies/lark/lexer.py +0 -678
- kucoin_api/ccxt/static_dependencies/lark/load_grammar.py +0 -1428
- kucoin_api/ccxt/static_dependencies/lark/parse_tree_builder.py +0 -391
- kucoin_api/ccxt/static_dependencies/lark/parser_frontends.py +0 -257
- kucoin_api/ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
- kucoin_api/ccxt/static_dependencies/lark/parsers/cyk.py +0 -340
- kucoin_api/ccxt/static_dependencies/lark/parsers/earley.py +0 -314
- kucoin_api/ccxt/static_dependencies/lark/parsers/earley_common.py +0 -42
- kucoin_api/ccxt/static_dependencies/lark/parsers/earley_forest.py +0 -801
- kucoin_api/ccxt/static_dependencies/lark/parsers/grammar_analysis.py +0 -203
- kucoin_api/ccxt/static_dependencies/lark/parsers/lalr_analysis.py +0 -332
- kucoin_api/ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +0 -158
- kucoin_api/ccxt/static_dependencies/lark/parsers/lalr_parser.py +0 -122
- kucoin_api/ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +0 -110
- kucoin_api/ccxt/static_dependencies/lark/parsers/xearley.py +0 -165
- kucoin_api/ccxt/static_dependencies/lark/py.typed +0 -0
- kucoin_api/ccxt/static_dependencies/lark/reconstruct.py +0 -107
- kucoin_api/ccxt/static_dependencies/lark/tools/__init__.py +0 -70
- kucoin_api/ccxt/static_dependencies/lark/tools/nearley.py +0 -202
- kucoin_api/ccxt/static_dependencies/lark/tools/serialize.py +0 -32
- kucoin_api/ccxt/static_dependencies/lark/tools/standalone.py +0 -196
- kucoin_api/ccxt/static_dependencies/lark/tree.py +0 -267
- kucoin_api/ccxt/static_dependencies/lark/tree_matcher.py +0 -186
- kucoin_api/ccxt/static_dependencies/lark/tree_templates.py +0 -180
- kucoin_api/ccxt/static_dependencies/lark/utils.py +0 -343
- kucoin_api/ccxt/static_dependencies/lark/visitors.py +0 -596
- kucoin_api/ccxt/static_dependencies/marshmallow/__init__.py +0 -81
- kucoin_api/ccxt/static_dependencies/marshmallow/base.py +0 -65
- kucoin_api/ccxt/static_dependencies/marshmallow/class_registry.py +0 -94
- kucoin_api/ccxt/static_dependencies/marshmallow/decorators.py +0 -231
- kucoin_api/ccxt/static_dependencies/marshmallow/error_store.py +0 -60
- kucoin_api/ccxt/static_dependencies/marshmallow/exceptions.py +0 -71
- kucoin_api/ccxt/static_dependencies/marshmallow/fields.py +0 -2114
- kucoin_api/ccxt/static_dependencies/marshmallow/orderedset.py +0 -89
- kucoin_api/ccxt/static_dependencies/marshmallow/py.typed +0 -0
- kucoin_api/ccxt/static_dependencies/marshmallow/schema.py +0 -1228
- kucoin_api/ccxt/static_dependencies/marshmallow/types.py +0 -12
- kucoin_api/ccxt/static_dependencies/marshmallow/utils.py +0 -378
- kucoin_api/ccxt/static_dependencies/marshmallow/validate.py +0 -678
- kucoin_api/ccxt/static_dependencies/marshmallow/warnings.py +0 -2
- kucoin_api/ccxt/static_dependencies/marshmallow_dataclass/__init__.py +0 -1047
- kucoin_api/ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +0 -51
- kucoin_api/ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +0 -45
- kucoin_api/ccxt/static_dependencies/marshmallow_dataclass/mypy.py +0 -71
- kucoin_api/ccxt/static_dependencies/marshmallow_dataclass/py.typed +0 -0
- kucoin_api/ccxt/static_dependencies/marshmallow_dataclass/typing.py +0 -14
- kucoin_api/ccxt/static_dependencies/marshmallow_dataclass/union_field.py +0 -82
- kucoin_api/ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +0 -1
- kucoin_api/ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +0 -193
- kucoin_api/ccxt/static_dependencies/marshmallow_oneofschema/py.typed +0 -0
- kucoin_api/ccxt/static_dependencies/msgpack/__init__.py +0 -55
- kucoin_api/ccxt/static_dependencies/msgpack/_cmsgpack.pyx +0 -11
- kucoin_api/ccxt/static_dependencies/msgpack/_packer.pyx +0 -374
- kucoin_api/ccxt/static_dependencies/msgpack/_unpacker.pyx +0 -547
- kucoin_api/ccxt/static_dependencies/msgpack/buff_converter.h +0 -8
- kucoin_api/ccxt/static_dependencies/msgpack/exceptions.py +0 -48
- kucoin_api/ccxt/static_dependencies/msgpack/ext.py +0 -168
- kucoin_api/ccxt/static_dependencies/msgpack/fallback.py +0 -951
- kucoin_api/ccxt/static_dependencies/msgpack/pack.h +0 -89
- kucoin_api/ccxt/static_dependencies/msgpack/pack_template.h +0 -820
- kucoin_api/ccxt/static_dependencies/msgpack/sysdep.h +0 -194
- kucoin_api/ccxt/static_dependencies/msgpack/unpack.h +0 -391
- kucoin_api/ccxt/static_dependencies/msgpack/unpack_define.h +0 -95
- kucoin_api/ccxt/static_dependencies/msgpack/unpack_template.h +0 -464
- kucoin_api/ccxt/static_dependencies/parsimonious/__init__.py +0 -10
- kucoin_api/ccxt/static_dependencies/parsimonious/exceptions.py +0 -105
- kucoin_api/ccxt/static_dependencies/parsimonious/expressions.py +0 -479
- kucoin_api/ccxt/static_dependencies/parsimonious/grammar.py +0 -487
- kucoin_api/ccxt/static_dependencies/parsimonious/nodes.py +0 -325
- kucoin_api/ccxt/static_dependencies/parsimonious/utils.py +0 -40
- kucoin_api/ccxt/static_dependencies/starknet/__init__.py +0 -0
- kucoin_api/ccxt/static_dependencies/starknet/abi/v0/__init__.py +0 -2
- kucoin_api/ccxt/static_dependencies/starknet/abi/v0/model.py +0 -44
- kucoin_api/ccxt/static_dependencies/starknet/abi/v0/parser.py +0 -216
- kucoin_api/ccxt/static_dependencies/starknet/abi/v0/schemas.py +0 -72
- kucoin_api/ccxt/static_dependencies/starknet/abi/v0/shape.py +0 -63
- kucoin_api/ccxt/static_dependencies/starknet/abi/v1/__init__.py +0 -2
- kucoin_api/ccxt/static_dependencies/starknet/abi/v1/core_structures.json +0 -14
- kucoin_api/ccxt/static_dependencies/starknet/abi/v1/model.py +0 -39
- kucoin_api/ccxt/static_dependencies/starknet/abi/v1/parser.py +0 -220
- kucoin_api/ccxt/static_dependencies/starknet/abi/v1/parser_transformer.py +0 -179
- kucoin_api/ccxt/static_dependencies/starknet/abi/v1/schemas.py +0 -66
- kucoin_api/ccxt/static_dependencies/starknet/abi/v1/shape.py +0 -47
- kucoin_api/ccxt/static_dependencies/starknet/abi/v2/__init__.py +0 -2
- kucoin_api/ccxt/static_dependencies/starknet/abi/v2/model.py +0 -89
- kucoin_api/ccxt/static_dependencies/starknet/abi/v2/parser.py +0 -293
- kucoin_api/ccxt/static_dependencies/starknet/abi/v2/parser_transformer.py +0 -192
- kucoin_api/ccxt/static_dependencies/starknet/abi/v2/schemas.py +0 -132
- kucoin_api/ccxt/static_dependencies/starknet/abi/v2/shape.py +0 -107
- kucoin_api/ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
- kucoin_api/ccxt/static_dependencies/starknet/cairo/data_types.py +0 -123
- kucoin_api/ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
- kucoin_api/ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +0 -77
- kucoin_api/ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +0 -46
- kucoin_api/ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +0 -138
- kucoin_api/ccxt/static_dependencies/starknet/cairo/felt.py +0 -64
- kucoin_api/ccxt/static_dependencies/starknet/cairo/type_parser.py +0 -121
- kucoin_api/ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
- kucoin_api/ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +0 -59
- kucoin_api/ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
- kucoin_api/ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +0 -77
- kucoin_api/ccxt/static_dependencies/starknet/ccxt_utils.py +0 -7
- kucoin_api/ccxt/static_dependencies/starknet/common.py +0 -15
- kucoin_api/ccxt/static_dependencies/starknet/constants.py +0 -39
- kucoin_api/ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
- kucoin_api/ccxt/static_dependencies/starknet/hash/address.py +0 -79
- kucoin_api/ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +0 -111
- kucoin_api/ccxt/static_dependencies/starknet/hash/selector.py +0 -16
- kucoin_api/ccxt/static_dependencies/starknet/hash/storage.py +0 -12
- kucoin_api/ccxt/static_dependencies/starknet/hash/utils.py +0 -78
- kucoin_api/ccxt/static_dependencies/starknet/models/__init__.py +0 -0
- kucoin_api/ccxt/static_dependencies/starknet/models/typed_data.py +0 -45
- kucoin_api/ccxt/static_dependencies/starknet/serialization/__init__.py +0 -24
- kucoin_api/ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +0 -40
- kucoin_api/ccxt/static_dependencies/starknet/serialization/_context.py +0 -142
- kucoin_api/ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +0 -10
- kucoin_api/ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +0 -82
- kucoin_api/ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +0 -43
- kucoin_api/ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +0 -37
- kucoin_api/ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +0 -66
- kucoin_api/ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +0 -71
- kucoin_api/ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +0 -71
- kucoin_api/ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +0 -50
- kucoin_api/ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +0 -58
- kucoin_api/ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +0 -43
- kucoin_api/ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +0 -40
- kucoin_api/ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +0 -72
- kucoin_api/ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +0 -36
- kucoin_api/ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +0 -36
- kucoin_api/ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +0 -76
- kucoin_api/ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +0 -100
- kucoin_api/ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +0 -32
- kucoin_api/ccxt/static_dependencies/starknet/serialization/errors.py +0 -10
- kucoin_api/ccxt/static_dependencies/starknet/serialization/factory.py +0 -229
- kucoin_api/ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +0 -110
- kucoin_api/ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +0 -59
- kucoin_api/ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
- kucoin_api/ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +0 -86
- kucoin_api/ccxt/static_dependencies/starknet/utils/iterable.py +0 -13
- kucoin_api/ccxt/static_dependencies/starknet/utils/schema.py +0 -13
- kucoin_api/ccxt/static_dependencies/starknet/utils/typed_data.py +0 -182
- kucoin_api/ccxt/static_dependencies/starkware/__init__.py +0 -0
- kucoin_api/ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
- kucoin_api/ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +0 -50
- kucoin_api/ccxt/static_dependencies/starkware/crypto/math_utils.py +0 -78
- kucoin_api/ccxt/static_dependencies/starkware/crypto/signature.py +0 -2344
- kucoin_api/ccxt/static_dependencies/starkware/crypto/utils.py +0 -63
- kucoin_api/ccxt/static_dependencies/sympy/__init__.py +0 -0
- kucoin_api/ccxt/static_dependencies/sympy/core/__init__.py +0 -0
- kucoin_api/ccxt/static_dependencies/sympy/core/intfunc.py +0 -35
- kucoin_api/ccxt/static_dependencies/sympy/external/__init__.py +0 -0
- kucoin_api/ccxt/static_dependencies/sympy/external/gmpy.py +0 -345
- kucoin_api/ccxt/static_dependencies/sympy/external/importtools.py +0 -187
- kucoin_api/ccxt/static_dependencies/sympy/external/ntheory.py +0 -637
- kucoin_api/ccxt/static_dependencies/sympy/external/pythonmpq.py +0 -341
- kucoin_api/ccxt/static_dependencies/toolz/__init__.py +0 -26
- kucoin_api/ccxt/static_dependencies/toolz/_signatures.py +0 -784
- kucoin_api/ccxt/static_dependencies/toolz/_version.py +0 -520
- kucoin_api/ccxt/static_dependencies/toolz/compatibility.py +0 -30
- kucoin_api/ccxt/static_dependencies/toolz/curried/__init__.py +0 -101
- kucoin_api/ccxt/static_dependencies/toolz/curried/exceptions.py +0 -22
- kucoin_api/ccxt/static_dependencies/toolz/curried/operator.py +0 -22
- kucoin_api/ccxt/static_dependencies/toolz/dicttoolz.py +0 -339
- kucoin_api/ccxt/static_dependencies/toolz/functoolz.py +0 -1049
- kucoin_api/ccxt/static_dependencies/toolz/itertoolz.py +0 -1057
- kucoin_api/ccxt/static_dependencies/toolz/recipes.py +0 -46
- kucoin_api/ccxt/static_dependencies/toolz/utils.py +0 -9
- kucoin_api/ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
- kucoin_api/ccxt/static_dependencies/typing_inspect/typing_inspect.py +0 -851
- kucoin_api-0.0.11.dist-info/RECORD +0 -288
- {kucoin_api-0.0.11.dist-info → kucoin_api-0.0.12.dist-info}/WHEEL +0 -0
kucoin_api/ccxt/pro/kucoin.py
DELETED
|
@@ -1,1356 +0,0 @@
|
|
|
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, ArrayCacheByTimestamp
|
|
8
|
-
from ccxt.base.types import Any, Balances, Int, Order, OrderBook, Str, Strings, Ticker, Tickers, Trade
|
|
9
|
-
from ccxt.async_support.base.ws.client import Client
|
|
10
|
-
from typing import List
|
|
11
|
-
from ccxt.base.errors import ExchangeError
|
|
12
|
-
from ccxt.base.errors import ArgumentsRequired
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
from ccxt.async_support import kucoin as kucoinAsync
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class kucoin(kucoinAsync):
|
|
19
|
-
|
|
20
|
-
def describe(self) -> Any:
|
|
21
|
-
return self.deep_extend(super(kucoin, self).describe(), {
|
|
22
|
-
'has': {
|
|
23
|
-
'ws': True,
|
|
24
|
-
'createOrderWs': False,
|
|
25
|
-
'editOrderWs': False,
|
|
26
|
-
'fetchOpenOrdersWs': False,
|
|
27
|
-
'fetchOrderWs': False,
|
|
28
|
-
'cancelOrderWs': False,
|
|
29
|
-
'cancelOrdersWs': False,
|
|
30
|
-
'cancelAllOrdersWs': False,
|
|
31
|
-
'watchBidsAsks': True,
|
|
32
|
-
'watchOrderBook': True,
|
|
33
|
-
'watchOrders': True,
|
|
34
|
-
'watchMyTrades': True,
|
|
35
|
-
'watchTickers': True,
|
|
36
|
-
'watchTicker': True,
|
|
37
|
-
'watchTrades': True,
|
|
38
|
-
'watchTradesForSymbols': True,
|
|
39
|
-
'watchOrderBookForSymbols': True,
|
|
40
|
-
'watchBalance': True,
|
|
41
|
-
'watchOHLCV': True,
|
|
42
|
-
},
|
|
43
|
-
'options': {
|
|
44
|
-
'tradesLimit': 1000,
|
|
45
|
-
'watchTicker': {
|
|
46
|
-
'name': 'market/snapshot', # market/ticker
|
|
47
|
-
},
|
|
48
|
-
'watchOrderBook': {
|
|
49
|
-
'snapshotDelay': 5,
|
|
50
|
-
'snapshotMaxRetries': 3,
|
|
51
|
-
'method': '/market/level2', # '/spotMarket/level2Depth5' or '/spotMarket/level2Depth50'
|
|
52
|
-
},
|
|
53
|
-
'watchMyTrades': {
|
|
54
|
-
'method': '/spotMarket/tradeOrders', # or '/spot/tradeFills'
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
'streaming': {
|
|
58
|
-
# kucoin does not support built-in ws protocol-level ping-pong
|
|
59
|
-
# instead it requires a custom json-based text ping-pong
|
|
60
|
-
# https://docs.kucoin.com/#ping
|
|
61
|
-
'ping': self.ping,
|
|
62
|
-
},
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
async def negotiate(self, privateChannel, params={}):
|
|
66
|
-
connectId = 'private' if privateChannel else 'public'
|
|
67
|
-
urls = self.safe_value(self.options, 'urls', {})
|
|
68
|
-
spawaned = self.safe_value(urls, connectId)
|
|
69
|
-
if spawaned is not None:
|
|
70
|
-
return await spawaned
|
|
71
|
-
# we store an awaitable to the url
|
|
72
|
-
# so that multiple calls don't asynchronously
|
|
73
|
-
# fetch different urls and overwrite each other
|
|
74
|
-
urls[connectId] = self.spawn(self.negotiate_helper, privateChannel, params)
|
|
75
|
-
self.options['urls'] = urls
|
|
76
|
-
future = urls[connectId]
|
|
77
|
-
return await future
|
|
78
|
-
|
|
79
|
-
async def negotiate_helper(self, privateChannel, params={}):
|
|
80
|
-
response = None
|
|
81
|
-
connectId = 'private' if privateChannel else 'public'
|
|
82
|
-
try:
|
|
83
|
-
if privateChannel:
|
|
84
|
-
response = await self.privatePostBulletPrivate(params)
|
|
85
|
-
#
|
|
86
|
-
# {
|
|
87
|
-
# "code": "200000",
|
|
88
|
-
# "data": {
|
|
89
|
-
# "instanceServers": [
|
|
90
|
-
# {
|
|
91
|
-
# "pingInterval": 50000,
|
|
92
|
-
# "endpoint": "wss://push-private.kucoin.com/endpoint",
|
|
93
|
-
# "protocol": "websocket",
|
|
94
|
-
# "encrypt": True,
|
|
95
|
-
# "pingTimeout": 10000
|
|
96
|
-
# }
|
|
97
|
-
# ],
|
|
98
|
-
# "token": "2neAiuYvAU61ZDXANAGAsiL4-iAExhsBXZxftpOeh_55i3Ysy2q2LEsEWU64mdzUOPusi34M_wGoSf7iNyEWJ1UQy47YbpY4zVdzilNP-Bj3iXzrjjGlWtiYB9J6i9GjsxUuhPw3BlrzazF6ghq4Lzf7scStOz3KkxjwpsOBCH4=.WNQmhZQeUKIkh97KYgU0Lg=="
|
|
99
|
-
# }
|
|
100
|
-
# }
|
|
101
|
-
#
|
|
102
|
-
else:
|
|
103
|
-
response = await self.publicPostBulletPublic(params)
|
|
104
|
-
data = self.safe_value(response, 'data', {})
|
|
105
|
-
instanceServers = self.safe_value(data, 'instanceServers', [])
|
|
106
|
-
firstInstanceServer = self.safe_value(instanceServers, 0)
|
|
107
|
-
pingInterval = self.safe_integer(firstInstanceServer, 'pingInterval')
|
|
108
|
-
endpoint = self.safe_string(firstInstanceServer, 'endpoint')
|
|
109
|
-
token = self.safe_string(data, 'token')
|
|
110
|
-
result = endpoint + '?' + self.urlencode({
|
|
111
|
-
'token': token,
|
|
112
|
-
'privateChannel': privateChannel,
|
|
113
|
-
'connectId': connectId,
|
|
114
|
-
})
|
|
115
|
-
client = self.client(result)
|
|
116
|
-
client.keepAlive = pingInterval
|
|
117
|
-
return result
|
|
118
|
-
except Exception as e:
|
|
119
|
-
future = self.safe_value(self.options['urls'], connectId)
|
|
120
|
-
future.reject(e)
|
|
121
|
-
del self.options['urls'][connectId]
|
|
122
|
-
return None
|
|
123
|
-
|
|
124
|
-
def request_id(self):
|
|
125
|
-
requestId = self.sum(self.safe_integer(self.options, 'requestId', 0), 1)
|
|
126
|
-
self.options['requestId'] = requestId
|
|
127
|
-
return requestId
|
|
128
|
-
|
|
129
|
-
async def subscribe(self, url, messageHash, subscriptionHash, params={}, subscription=None):
|
|
130
|
-
requestId = str(self.request_id())
|
|
131
|
-
request: dict = {
|
|
132
|
-
'id': requestId,
|
|
133
|
-
'type': 'subscribe',
|
|
134
|
-
'topic': subscriptionHash,
|
|
135
|
-
'response': True,
|
|
136
|
-
}
|
|
137
|
-
message = self.extend(request, params)
|
|
138
|
-
client = self.client(url)
|
|
139
|
-
if not (subscriptionHash in client.subscriptions):
|
|
140
|
-
client.subscriptions[requestId] = subscriptionHash
|
|
141
|
-
return await self.watch(url, messageHash, message, subscriptionHash, subscription)
|
|
142
|
-
|
|
143
|
-
async def subscribe_multiple(self, url, messageHashes, topic, subscriptionHashes, params={}, subscription=None):
|
|
144
|
-
requestId = str(self.request_id())
|
|
145
|
-
request: dict = {
|
|
146
|
-
'id': requestId,
|
|
147
|
-
'type': 'subscribe',
|
|
148
|
-
'topic': topic,
|
|
149
|
-
'response': True,
|
|
150
|
-
}
|
|
151
|
-
message = self.extend(request, params)
|
|
152
|
-
client = self.client(url)
|
|
153
|
-
for i in range(0, len(subscriptionHashes)):
|
|
154
|
-
subscriptionHash = subscriptionHashes[i]
|
|
155
|
-
if not (subscriptionHash in client.subscriptions):
|
|
156
|
-
client.subscriptions[requestId] = subscriptionHash
|
|
157
|
-
return await self.watch_multiple(url, messageHashes, message, subscriptionHashes, subscription)
|
|
158
|
-
|
|
159
|
-
async def un_subscribe_multiple(self, url, messageHashes, topic, subscriptionHashes, params={}, subscription: dict = None):
|
|
160
|
-
requestId = str(self.request_id())
|
|
161
|
-
request: dict = {
|
|
162
|
-
'id': requestId,
|
|
163
|
-
'type': 'unsubscribe',
|
|
164
|
-
'topic': topic,
|
|
165
|
-
'response': True,
|
|
166
|
-
}
|
|
167
|
-
message = self.extend(request, params)
|
|
168
|
-
if subscription is not None:
|
|
169
|
-
subscription[requestId] = requestId
|
|
170
|
-
client = self.client(url)
|
|
171
|
-
for i in range(0, len(subscriptionHashes)):
|
|
172
|
-
subscriptionHash = subscriptionHashes[i]
|
|
173
|
-
if not (subscriptionHash in client.subscriptions):
|
|
174
|
-
client.subscriptions[requestId] = subscriptionHash
|
|
175
|
-
return await self.watch_multiple(url, messageHashes, message, subscriptionHashes, subscription)
|
|
176
|
-
|
|
177
|
-
async def watch_ticker(self, symbol: str, params={}) -> Ticker:
|
|
178
|
-
"""
|
|
179
|
-
watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
|
180
|
-
|
|
181
|
-
https://www.kucoin.com/docs/websocket/spot-trading/public-channels/market-snapshot
|
|
182
|
-
|
|
183
|
-
:param str symbol: unified symbol of the market to fetch the ticker for
|
|
184
|
-
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
185
|
-
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
186
|
-
"""
|
|
187
|
-
await self.load_markets()
|
|
188
|
-
market = self.market(symbol)
|
|
189
|
-
symbol = market['symbol']
|
|
190
|
-
url = await self.negotiate(False)
|
|
191
|
-
method, query = self.handle_option_and_params(params, 'watchTicker', 'method', '/market/snapshot')
|
|
192
|
-
topic = method + ':' + market['id']
|
|
193
|
-
messageHash = 'ticker:' + symbol
|
|
194
|
-
return await self.subscribe(url, messageHash, topic, query)
|
|
195
|
-
|
|
196
|
-
async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
|
|
197
|
-
"""
|
|
198
|
-
|
|
199
|
-
https://www.kucoin.com/docs/websocket/spot-trading/public-channels/ticker
|
|
200
|
-
|
|
201
|
-
watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
|
|
202
|
-
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
|
203
|
-
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
204
|
-
:param str [params.method]: either '/market/snapshot' or '/market/ticker' default is '/market/ticker'
|
|
205
|
-
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
206
|
-
"""
|
|
207
|
-
await self.load_markets()
|
|
208
|
-
symbols = self.market_symbols(symbols)
|
|
209
|
-
messageHash = 'tickers'
|
|
210
|
-
method = None
|
|
211
|
-
method, params = self.handle_option_and_params(params, 'watchTickers', 'method', '/market/ticker')
|
|
212
|
-
messageHashes = []
|
|
213
|
-
topics = []
|
|
214
|
-
if symbols is not None:
|
|
215
|
-
for i in range(0, len(symbols)):
|
|
216
|
-
symbol = symbols[i]
|
|
217
|
-
messageHashes.append('ticker:' + symbol)
|
|
218
|
-
market = self.market(symbol)
|
|
219
|
-
topics.append(method + ':' + market['id'])
|
|
220
|
-
url = await self.negotiate(False)
|
|
221
|
-
tickers = None
|
|
222
|
-
if symbols is None:
|
|
223
|
-
allTopic = method + ':all'
|
|
224
|
-
tickers = await self.subscribe(url, messageHash, allTopic, params)
|
|
225
|
-
if self.newUpdates:
|
|
226
|
-
return tickers
|
|
227
|
-
else:
|
|
228
|
-
marketIds = self.market_ids(symbols)
|
|
229
|
-
symbolsTopic = method + ':' + ','.join(marketIds)
|
|
230
|
-
tickers = await self.subscribe_multiple(url, messageHashes, symbolsTopic, topics, params)
|
|
231
|
-
if self.newUpdates:
|
|
232
|
-
newDict: dict = {}
|
|
233
|
-
newDict[tickers['symbol']] = tickers
|
|
234
|
-
return newDict
|
|
235
|
-
return self.filter_by_array(self.tickers, 'symbol', symbols)
|
|
236
|
-
|
|
237
|
-
def handle_ticker(self, client: Client, message):
|
|
238
|
-
#
|
|
239
|
-
# market/snapshot
|
|
240
|
-
#
|
|
241
|
-
# updates come in every 2 sec unless there
|
|
242
|
-
# were no changes since the previous update
|
|
243
|
-
#
|
|
244
|
-
# {
|
|
245
|
-
# "data": {
|
|
246
|
-
# "sequence": "1545896669291",
|
|
247
|
-
# "data": {
|
|
248
|
-
# "trading": True,
|
|
249
|
-
# "symbol": "KCS-BTC",
|
|
250
|
-
# "buy": 0.00011,
|
|
251
|
-
# "sell": 0.00012,
|
|
252
|
-
# "sort": 100,
|
|
253
|
-
# "volValue": 3.13851792584, # total
|
|
254
|
-
# "baseCurrency": "KCS",
|
|
255
|
-
# "market": "BTC",
|
|
256
|
-
# "quoteCurrency": "BTC",
|
|
257
|
-
# "symbolCode": "KCS-BTC",
|
|
258
|
-
# "datetime": 1548388122031,
|
|
259
|
-
# "high": 0.00013,
|
|
260
|
-
# "vol": 27514.34842,
|
|
261
|
-
# "low": 0.0001,
|
|
262
|
-
# "changePrice": -1.0e-5,
|
|
263
|
-
# "changeRate": -0.0769,
|
|
264
|
-
# "lastTradedPrice": 0.00012,
|
|
265
|
-
# "board": 0,
|
|
266
|
-
# "mark": 0
|
|
267
|
-
# }
|
|
268
|
-
# },
|
|
269
|
-
# "subject": "trade.snapshot",
|
|
270
|
-
# "topic": "/market/snapshot:KCS-BTC",
|
|
271
|
-
# "type": "message"
|
|
272
|
-
# }
|
|
273
|
-
#
|
|
274
|
-
# market/ticker
|
|
275
|
-
#
|
|
276
|
-
# {
|
|
277
|
-
# "type": "message",
|
|
278
|
-
# "topic": "/market/ticker:BTC-USDT",
|
|
279
|
-
# "subject": "trade.ticker",
|
|
280
|
-
# "data": {
|
|
281
|
-
# "bestAsk": "62163",
|
|
282
|
-
# "bestAskSize": "0.99011388",
|
|
283
|
-
# "bestBid": "62162.9",
|
|
284
|
-
# "bestBidSize": "0.04794181",
|
|
285
|
-
# "price": "62162.9",
|
|
286
|
-
# "sequence": "1621383371852",
|
|
287
|
-
# "size": "0.00832274",
|
|
288
|
-
# "time": 1634641987564
|
|
289
|
-
# }
|
|
290
|
-
# }
|
|
291
|
-
#
|
|
292
|
-
topic = self.safe_string(message, 'topic')
|
|
293
|
-
market = None
|
|
294
|
-
if topic is not None:
|
|
295
|
-
parts = topic.split(':')
|
|
296
|
-
first = self.safe_string(parts, 1)
|
|
297
|
-
marketId = None
|
|
298
|
-
if first == 'all':
|
|
299
|
-
marketId = self.safe_string(message, 'subject')
|
|
300
|
-
else:
|
|
301
|
-
marketId = first
|
|
302
|
-
market = self.safe_market(marketId, market, '-')
|
|
303
|
-
data = self.safe_value(message, 'data', {})
|
|
304
|
-
rawTicker = self.safe_value(data, 'data', data)
|
|
305
|
-
ticker = self.parse_ticker(rawTicker, market)
|
|
306
|
-
symbol = ticker['symbol']
|
|
307
|
-
self.tickers[symbol] = ticker
|
|
308
|
-
messageHash = 'ticker:' + symbol
|
|
309
|
-
client.resolve(ticker, messageHash)
|
|
310
|
-
# watchTickers
|
|
311
|
-
allTickers: dict = {}
|
|
312
|
-
allTickers[symbol] = ticker
|
|
313
|
-
client.resolve(allTickers, 'tickers')
|
|
314
|
-
|
|
315
|
-
async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
|
|
316
|
-
"""
|
|
317
|
-
|
|
318
|
-
https://www.kucoin.com/docs/websocket/spot-trading/public-channels/level1-bbo-market-data
|
|
319
|
-
|
|
320
|
-
watches best bid & ask for symbols
|
|
321
|
-
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
|
322
|
-
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
323
|
-
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
324
|
-
"""
|
|
325
|
-
ticker = await self.watch_multi_helper('watchBidsAsks', '/spotMarket/level1:', symbols, params)
|
|
326
|
-
if self.newUpdates:
|
|
327
|
-
tickers: dict = {}
|
|
328
|
-
tickers[ticker['symbol']] = ticker
|
|
329
|
-
return tickers
|
|
330
|
-
return self.filter_by_array(self.bidsasks, 'symbol', symbols)
|
|
331
|
-
|
|
332
|
-
async def watch_multi_helper(self, methodName, channelName: str, symbols: Strings = None, params={}):
|
|
333
|
-
await self.load_markets()
|
|
334
|
-
symbols = self.market_symbols(symbols, None, False, True, False)
|
|
335
|
-
length = len(symbols)
|
|
336
|
-
if length > 100:
|
|
337
|
-
raise ArgumentsRequired(self.id + ' ' + methodName + '() accepts a maximum of 100 symbols')
|
|
338
|
-
messageHashes = []
|
|
339
|
-
for i in range(0, len(symbols)):
|
|
340
|
-
symbol = symbols[i]
|
|
341
|
-
market = self.market(symbol)
|
|
342
|
-
messageHashes.append('bidask@' + market['symbol'])
|
|
343
|
-
url = await self.negotiate(False)
|
|
344
|
-
marketIds = self.market_ids(symbols)
|
|
345
|
-
joined = ','.join(marketIds)
|
|
346
|
-
requestId = str(self.request_id())
|
|
347
|
-
request: dict = {
|
|
348
|
-
'id': requestId,
|
|
349
|
-
'type': 'subscribe',
|
|
350
|
-
'topic': channelName + joined,
|
|
351
|
-
'response': True,
|
|
352
|
-
}
|
|
353
|
-
message = self.extend(request, params)
|
|
354
|
-
return await self.watch_multiple(url, messageHashes, message, messageHashes)
|
|
355
|
-
|
|
356
|
-
def handle_bid_ask(self, client: Client, message):
|
|
357
|
-
#
|
|
358
|
-
# arrives one symbol dict
|
|
359
|
-
#
|
|
360
|
-
# {
|
|
361
|
-
# topic: '/spotMarket/level1:ETH-USDT',
|
|
362
|
-
# type: 'message',
|
|
363
|
-
# data: {
|
|
364
|
-
# asks: ['3347.42', '2.0778387'],
|
|
365
|
-
# bids: ['3347.41', '6.0411697'],
|
|
366
|
-
# timestamp: 1712231142085
|
|
367
|
-
# },
|
|
368
|
-
# subject: 'level1'
|
|
369
|
-
# }
|
|
370
|
-
#
|
|
371
|
-
parsedTicker = self.parse_ws_bid_ask(message)
|
|
372
|
-
symbol = parsedTicker['symbol']
|
|
373
|
-
self.bidsasks[symbol] = parsedTicker
|
|
374
|
-
messageHash = 'bidask@' + symbol
|
|
375
|
-
client.resolve(parsedTicker, messageHash)
|
|
376
|
-
|
|
377
|
-
def parse_ws_bid_ask(self, ticker, market=None):
|
|
378
|
-
topic = self.safe_string(ticker, 'topic')
|
|
379
|
-
parts = topic.split(':')
|
|
380
|
-
marketId = parts[1]
|
|
381
|
-
market = self.safe_market(marketId, market)
|
|
382
|
-
symbol = self.safe_string(market, 'symbol')
|
|
383
|
-
data = self.safe_dict(ticker, 'data', {})
|
|
384
|
-
ask = self.safe_list(data, 'asks', [])
|
|
385
|
-
bid = self.safe_list(data, 'bids', [])
|
|
386
|
-
timestamp = self.safe_integer(data, 'timestamp')
|
|
387
|
-
return self.safe_ticker({
|
|
388
|
-
'symbol': symbol,
|
|
389
|
-
'timestamp': timestamp,
|
|
390
|
-
'datetime': self.iso8601(timestamp),
|
|
391
|
-
'ask': self.safe_number(ask, 0),
|
|
392
|
-
'askVolume': self.safe_number(ask, 1),
|
|
393
|
-
'bid': self.safe_number(bid, 0),
|
|
394
|
-
'bidVolume': self.safe_number(bid, 1),
|
|
395
|
-
'info': ticker,
|
|
396
|
-
}, market)
|
|
397
|
-
|
|
398
|
-
async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
|
399
|
-
"""
|
|
400
|
-
watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
401
|
-
|
|
402
|
-
https://www.kucoin.com/docs/websocket/spot-trading/public-channels/klines
|
|
403
|
-
|
|
404
|
-
:param str symbol: unified symbol of the market to fetch OHLCV data for
|
|
405
|
-
:param str timeframe: the length of time each candle represents
|
|
406
|
-
:param int [since]: timestamp in ms of the earliest candle to fetch
|
|
407
|
-
:param int [limit]: the maximum amount of candles to fetch
|
|
408
|
-
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
409
|
-
:returns int[][]: A list of candles ordered, open, high, low, close, volume
|
|
410
|
-
"""
|
|
411
|
-
await self.load_markets()
|
|
412
|
-
url = await self.negotiate(False)
|
|
413
|
-
market = self.market(symbol)
|
|
414
|
-
symbol = market['symbol']
|
|
415
|
-
period = self.safe_string(self.timeframes, timeframe, timeframe)
|
|
416
|
-
topic = '/market/candles:' + market['id'] + '_' + period
|
|
417
|
-
messageHash = 'candles:' + symbol + ':' + timeframe
|
|
418
|
-
ohlcv = await self.subscribe(url, messageHash, topic, params)
|
|
419
|
-
if self.newUpdates:
|
|
420
|
-
limit = ohlcv.getLimit(symbol, limit)
|
|
421
|
-
return self.filter_by_since_limit(ohlcv, since, limit, 0, True)
|
|
422
|
-
|
|
423
|
-
def handle_ohlcv(self, client: Client, message):
|
|
424
|
-
#
|
|
425
|
-
# {
|
|
426
|
-
# "data": {
|
|
427
|
-
# "symbol": "BTC-USDT",
|
|
428
|
-
# "candles": [
|
|
429
|
-
# "1624881240",
|
|
430
|
-
# "34138.8",
|
|
431
|
-
# "34121.6",
|
|
432
|
-
# "34138.8",
|
|
433
|
-
# "34097.9",
|
|
434
|
-
# "3.06097133",
|
|
435
|
-
# "104430.955068564"
|
|
436
|
-
# ],
|
|
437
|
-
# "time": 1624881284466023700
|
|
438
|
-
# },
|
|
439
|
-
# "subject": "trade.candles.update",
|
|
440
|
-
# "topic": "/market/candles:BTC-USDT_1min",
|
|
441
|
-
# "type": "message"
|
|
442
|
-
# }
|
|
443
|
-
#
|
|
444
|
-
data = self.safe_value(message, 'data', {})
|
|
445
|
-
marketId = self.safe_string(data, 'symbol')
|
|
446
|
-
candles = self.safe_value(data, 'candles', [])
|
|
447
|
-
topic = self.safe_string(message, 'topic')
|
|
448
|
-
parts = topic.split('_')
|
|
449
|
-
interval = self.safe_string(parts, 1)
|
|
450
|
-
# use a reverse lookup in a static map instead
|
|
451
|
-
timeframe = self.find_timeframe(interval)
|
|
452
|
-
market = self.safe_market(marketId)
|
|
453
|
-
symbol = market['symbol']
|
|
454
|
-
messageHash = 'candles:' + symbol + ':' + timeframe
|
|
455
|
-
self.ohlcvs[symbol] = self.safe_value(self.ohlcvs, symbol, {})
|
|
456
|
-
stored = self.safe_value(self.ohlcvs[symbol], timeframe)
|
|
457
|
-
if stored is None:
|
|
458
|
-
limit = self.safe_integer(self.options, 'OHLCVLimit', 1000)
|
|
459
|
-
stored = ArrayCacheByTimestamp(limit)
|
|
460
|
-
self.ohlcvs[symbol][timeframe] = stored
|
|
461
|
-
ohlcv = self.parse_ohlcv(candles, market)
|
|
462
|
-
stored.append(ohlcv)
|
|
463
|
-
client.resolve(stored, messageHash)
|
|
464
|
-
|
|
465
|
-
async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
|
466
|
-
"""
|
|
467
|
-
get the list of most recent trades for a particular symbol
|
|
468
|
-
|
|
469
|
-
https://www.kucoin.com/docs/websocket/spot-trading/public-channels/match-execution-data
|
|
470
|
-
|
|
471
|
-
:param str symbol: unified symbol of the market to fetch trades for
|
|
472
|
-
:param int [since]: timestamp in ms of the earliest trade to fetch
|
|
473
|
-
:param int [limit]: the maximum amount of trades to fetch
|
|
474
|
-
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
475
|
-
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
|
476
|
-
"""
|
|
477
|
-
return await self.watch_trades_for_symbols([symbol], since, limit, params)
|
|
478
|
-
|
|
479
|
-
async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
|
480
|
-
"""
|
|
481
|
-
get the list of most recent trades for a particular symbol
|
|
482
|
-
|
|
483
|
-
https://www.kucoin.com/docs/websocket/spot-trading/public-channels/match-execution-data
|
|
484
|
-
|
|
485
|
-
:param str[] symbols:
|
|
486
|
-
:param int [since]: timestamp in ms of the earliest trade to fetch
|
|
487
|
-
:param int [limit]: the maximum amount of trades to fetch
|
|
488
|
-
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
489
|
-
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
|
490
|
-
"""
|
|
491
|
-
symbolsLength = len(symbols)
|
|
492
|
-
if symbolsLength == 0:
|
|
493
|
-
raise ArgumentsRequired(self.id + ' watchTradesForSymbols() requires a non-empty array of symbols')
|
|
494
|
-
await self.load_markets()
|
|
495
|
-
symbols = self.market_symbols(symbols)
|
|
496
|
-
marketIds = self.market_ids(symbols)
|
|
497
|
-
url = await self.negotiate(False)
|
|
498
|
-
messageHashes = []
|
|
499
|
-
subscriptionHashes = []
|
|
500
|
-
topic = '/market/match:' + ','.join(marketIds)
|
|
501
|
-
for i in range(0, len(symbols)):
|
|
502
|
-
symbol = symbols[i]
|
|
503
|
-
messageHashes.append('trades:' + symbol)
|
|
504
|
-
marketId = marketIds[i]
|
|
505
|
-
subscriptionHashes.append('/market/match:' + marketId)
|
|
506
|
-
trades = await self.subscribe_multiple(url, messageHashes, topic, subscriptionHashes, params)
|
|
507
|
-
if self.newUpdates:
|
|
508
|
-
first = self.safe_value(trades, 0)
|
|
509
|
-
tradeSymbol = self.safe_string(first, 'symbol')
|
|
510
|
-
limit = trades.getLimit(tradeSymbol, limit)
|
|
511
|
-
return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
|
|
512
|
-
|
|
513
|
-
async def un_watch_trades_for_symbols(self, symbols: List[str], params={}) -> Any:
|
|
514
|
-
"""
|
|
515
|
-
unWatches trades stream
|
|
516
|
-
|
|
517
|
-
https://www.kucoin.com/docs/websocket/spot-trading/public-channels/match-execution-data
|
|
518
|
-
|
|
519
|
-
:param str symbols:
|
|
520
|
-
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
521
|
-
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
|
522
|
-
"""
|
|
523
|
-
await self.load_markets()
|
|
524
|
-
symbols = self.market_symbols(symbols, None, False)
|
|
525
|
-
marketIds = self.market_ids(symbols)
|
|
526
|
-
url = await self.negotiate(False)
|
|
527
|
-
messageHashes = []
|
|
528
|
-
subscriptionHashes = []
|
|
529
|
-
topic = '/market/match:' + ','.join(marketIds)
|
|
530
|
-
for i in range(0, len(symbols)):
|
|
531
|
-
symbol = symbols[i]
|
|
532
|
-
messageHashes.append('unsubscribe:trades:' + symbol)
|
|
533
|
-
subscriptionHashes.append('trades:' + symbol)
|
|
534
|
-
subscription = {
|
|
535
|
-
'messageHashes': messageHashes,
|
|
536
|
-
'subMessageHashes': subscriptionHashes,
|
|
537
|
-
'topic': 'trades',
|
|
538
|
-
'unsubscribe': True,
|
|
539
|
-
'symbols': symbols,
|
|
540
|
-
}
|
|
541
|
-
return await self.un_subscribe_multiple(url, messageHashes, topic, messageHashes, params, subscription)
|
|
542
|
-
|
|
543
|
-
async def un_watch_trades(self, symbol: str, params={}) -> Any:
|
|
544
|
-
"""
|
|
545
|
-
unWatches trades stream
|
|
546
|
-
|
|
547
|
-
https://www.kucoin.com/docs/websocket/spot-trading/public-channels/match-execution-data
|
|
548
|
-
|
|
549
|
-
:param str symbol: unified symbol of the market to fetch trades for
|
|
550
|
-
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
551
|
-
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
|
552
|
-
"""
|
|
553
|
-
return await self.un_watch_trades_for_symbols([symbol], params)
|
|
554
|
-
|
|
555
|
-
def handle_trade(self, client: Client, message):
|
|
556
|
-
#
|
|
557
|
-
# {
|
|
558
|
-
# "data": {
|
|
559
|
-
# "sequence": "1568787654360",
|
|
560
|
-
# "symbol": "BTC-USDT",
|
|
561
|
-
# "side": "buy",
|
|
562
|
-
# "size": "0.00536577",
|
|
563
|
-
# "price": "9345",
|
|
564
|
-
# "takerOrderId": "5e356c4a9f1a790008f8d921",
|
|
565
|
-
# "time": "1580559434436443257",
|
|
566
|
-
# "type": "match",
|
|
567
|
-
# "makerOrderId": "5e356bffedf0010008fa5d7f",
|
|
568
|
-
# "tradeId": "5e356c4aeefabd62c62a1ece"
|
|
569
|
-
# },
|
|
570
|
-
# "subject": "trade.l3match",
|
|
571
|
-
# "topic": "/market/match:BTC-USDT",
|
|
572
|
-
# "type": "message"
|
|
573
|
-
# }
|
|
574
|
-
#
|
|
575
|
-
data = self.safe_value(message, 'data', {})
|
|
576
|
-
trade = self.parse_trade(data)
|
|
577
|
-
symbol = trade['symbol']
|
|
578
|
-
messageHash = 'trades:' + symbol
|
|
579
|
-
trades = self.safe_value(self.trades, symbol)
|
|
580
|
-
if trades is None:
|
|
581
|
-
limit = self.safe_integer(self.options, 'tradesLimit', 1000)
|
|
582
|
-
trades = ArrayCache(limit)
|
|
583
|
-
self.trades[symbol] = trades
|
|
584
|
-
trades.append(trade)
|
|
585
|
-
client.resolve(trades, messageHash)
|
|
586
|
-
|
|
587
|
-
async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
|
|
588
|
-
"""
|
|
589
|
-
|
|
590
|
-
https://www.kucoin.com/docs/websocket/spot-trading/public-channels/level1-bbo-market-data
|
|
591
|
-
https://www.kucoin.com/docs/websocket/spot-trading/public-channels/level2-market-data
|
|
592
|
-
https://www.kucoin.com/docs/websocket/spot-trading/public-channels/level2-5-best-ask-bid-orders
|
|
593
|
-
https://www.kucoin.com/docs/websocket/spot-trading/public-channels/level2-50-best-ask-bid-orders
|
|
594
|
-
|
|
595
|
-
watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
|
596
|
-
:param str symbol: unified symbol of the market to fetch the order book for
|
|
597
|
-
:param int [limit]: the maximum amount of order book entries to return
|
|
598
|
-
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
599
|
-
:param str [params.method]: either '/market/level2' or '/spotMarket/level2Depth5' or '/spotMarket/level2Depth50' default is '/market/level2'
|
|
600
|
-
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
|
|
601
|
-
"""
|
|
602
|
-
#
|
|
603
|
-
# https://docs.kucoin.com/#level-2-market-data
|
|
604
|
-
#
|
|
605
|
-
# 1. After receiving the websocket Level 2 data flow, cache the data.
|
|
606
|
-
# 2. Initiate a REST request to get the snapshot data of Level 2 order book.
|
|
607
|
-
# 3. Playback the cached Level 2 data flow.
|
|
608
|
-
# 4. Apply the new Level 2 data flow to the local snapshot to ensure that
|
|
609
|
-
# the sequence of the new Level 2 update lines up with the sequence of
|
|
610
|
-
# the previous Level 2 data. Discard all the message prior to that
|
|
611
|
-
# sequence, and then playback the change to snapshot.
|
|
612
|
-
# 5. Update the level2 full data based on sequence according to the
|
|
613
|
-
# size. If the price is 0, ignore the messages and update the sequence.
|
|
614
|
-
# If the size=0, update the sequence and remove the price of which the
|
|
615
|
-
# size is 0 out of level 2. Fr other cases, please update the price.
|
|
616
|
-
#
|
|
617
|
-
return await self.watch_order_book_for_symbols([symbol], limit, params)
|
|
618
|
-
|
|
619
|
-
async def un_watch_order_book(self, symbol: str, params={}) -> Any:
|
|
620
|
-
"""
|
|
621
|
-
|
|
622
|
-
https://www.kucoin.com/docs/websocket/spot-trading/public-channels/level1-bbo-market-data
|
|
623
|
-
https://www.kucoin.com/docs/websocket/spot-trading/public-channels/level2-market-data
|
|
624
|
-
https://www.kucoin.com/docs/websocket/spot-trading/public-channels/level2-5-best-ask-bid-orders
|
|
625
|
-
https://www.kucoin.com/docs/websocket/spot-trading/public-channels/level2-50-best-ask-bid-orders
|
|
626
|
-
|
|
627
|
-
unWatches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
|
628
|
-
:param str symbol: unified symbol of the market to fetch the order book for
|
|
629
|
-
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
630
|
-
:param str [params.method]: either '/market/level2' or '/spotMarket/level2Depth5' or '/spotMarket/level2Depth50' default is '/market/level2'
|
|
631
|
-
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
|
|
632
|
-
"""
|
|
633
|
-
return await self.un_watch_order_book_for_symbols([symbol], params)
|
|
634
|
-
|
|
635
|
-
async def watch_order_book_for_symbols(self, symbols: List[str], limit: Int = None, params={}) -> OrderBook:
|
|
636
|
-
"""
|
|
637
|
-
|
|
638
|
-
https://www.kucoin.com/docs/websocket/spot-trading/public-channels/level1-bbo-market-data
|
|
639
|
-
https://www.kucoin.com/docs/websocket/spot-trading/public-channels/level2-market-data
|
|
640
|
-
https://www.kucoin.com/docs/websocket/spot-trading/public-channels/level2-5-best-ask-bid-orders
|
|
641
|
-
https://www.kucoin.com/docs/websocket/spot-trading/public-channels/level2-50-best-ask-bid-orders
|
|
642
|
-
|
|
643
|
-
watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
|
644
|
-
:param str[] symbols: unified array of symbols
|
|
645
|
-
:param int [limit]: the maximum amount of order book entries to return
|
|
646
|
-
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
647
|
-
:param str [params.method]: either '/market/level2' or '/spotMarket/level2Depth5' or '/spotMarket/level2Depth50' default is '/market/level2'
|
|
648
|
-
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
|
|
649
|
-
"""
|
|
650
|
-
symbolsLength = len(symbols)
|
|
651
|
-
if symbolsLength == 0:
|
|
652
|
-
raise ArgumentsRequired(self.id + ' watchOrderBookForSymbols() requires a non-empty array of symbols')
|
|
653
|
-
if limit is not None:
|
|
654
|
-
if (limit != 20) and (limit != 100) and (limit != 50) and (limit != 5):
|
|
655
|
-
raise ExchangeError(self.id + " watchOrderBook 'limit' argument must be None, 5, 20, 50 or 100")
|
|
656
|
-
await self.load_markets()
|
|
657
|
-
symbols = self.market_symbols(symbols)
|
|
658
|
-
marketIds = self.market_ids(symbols)
|
|
659
|
-
url = await self.negotiate(False)
|
|
660
|
-
method: Str = None
|
|
661
|
-
method, params = self.handle_option_and_params(params, 'watchOrderBook', 'method', '/market/level2')
|
|
662
|
-
if (limit == 5) or (limit == 50):
|
|
663
|
-
method = '/spotMarket/level2Depth' + str(limit)
|
|
664
|
-
topic = method + ':' + ','.join(marketIds)
|
|
665
|
-
messageHashes = []
|
|
666
|
-
subscriptionHashes = []
|
|
667
|
-
for i in range(0, len(symbols)):
|
|
668
|
-
symbol = symbols[i]
|
|
669
|
-
messageHashes.append('orderbook:' + symbol)
|
|
670
|
-
marketId = marketIds[i]
|
|
671
|
-
subscriptionHashes.append(method + ':' + marketId)
|
|
672
|
-
subscription = {}
|
|
673
|
-
if method == '/market/level2': # other streams return the entire orderbook, so we don't need to fetch the snapshot through REST
|
|
674
|
-
subscription = {
|
|
675
|
-
'method': self.handle_order_book_subscription,
|
|
676
|
-
'symbols': symbols,
|
|
677
|
-
'limit': limit,
|
|
678
|
-
}
|
|
679
|
-
orderbook = await self.subscribe_multiple(url, messageHashes, topic, subscriptionHashes, params, subscription)
|
|
680
|
-
return orderbook.limit()
|
|
681
|
-
|
|
682
|
-
async def un_watch_order_book_for_symbols(self, symbols: List[str], params={}) -> Any:
|
|
683
|
-
"""
|
|
684
|
-
|
|
685
|
-
https://www.kucoin.com/docs/websocket/spot-trading/public-channels/level1-bbo-market-data
|
|
686
|
-
https://www.kucoin.com/docs/websocket/spot-trading/public-channels/level2-market-data
|
|
687
|
-
https://www.kucoin.com/docs/websocket/spot-trading/public-channels/level2-5-best-ask-bid-orders
|
|
688
|
-
https://www.kucoin.com/docs/websocket/spot-trading/public-channels/level2-50-best-ask-bid-orders
|
|
689
|
-
|
|
690
|
-
unWatches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
|
691
|
-
:param str[] symbols: unified array of symbols
|
|
692
|
-
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
693
|
-
:param str [params.method]: either '/market/level2' or '/spotMarket/level2Depth5' or '/spotMarket/level2Depth50' default is '/market/level2'
|
|
694
|
-
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
|
|
695
|
-
"""
|
|
696
|
-
limit = self.safe_integer(params, 'limit')
|
|
697
|
-
params = self.omit(params, 'limit')
|
|
698
|
-
await self.load_markets()
|
|
699
|
-
symbols = self.market_symbols(symbols, None, False)
|
|
700
|
-
marketIds = self.market_ids(symbols)
|
|
701
|
-
url = await self.negotiate(False)
|
|
702
|
-
method: Str = None
|
|
703
|
-
method, params = self.handle_option_and_params(params, 'watchOrderBook', 'method', '/market/level2')
|
|
704
|
-
if (limit == 5) or (limit == 50):
|
|
705
|
-
method = '/spotMarket/level2Depth' + str(limit)
|
|
706
|
-
topic = method + ':' + ','.join(marketIds)
|
|
707
|
-
messageHashes = []
|
|
708
|
-
subscriptionHashes = []
|
|
709
|
-
for i in range(0, len(symbols)):
|
|
710
|
-
symbol = symbols[i]
|
|
711
|
-
messageHashes.append('unsubscribe:orderbook:' + symbol)
|
|
712
|
-
subscriptionHashes.append('orderbook:' + symbol)
|
|
713
|
-
subscription = {
|
|
714
|
-
'messageHashes': messageHashes,
|
|
715
|
-
'symbols': symbols,
|
|
716
|
-
'unsubscribe': True,
|
|
717
|
-
'topic': 'orderbook',
|
|
718
|
-
'subMessageHashes': subscriptionHashes,
|
|
719
|
-
}
|
|
720
|
-
return await self.un_subscribe_multiple(url, messageHashes, topic, messageHashes, params, subscription)
|
|
721
|
-
|
|
722
|
-
def handle_order_book(self, client: Client, message):
|
|
723
|
-
#
|
|
724
|
-
# initial snapshot is fetched with ccxt's fetchOrderBook
|
|
725
|
-
# the feed does not include a snapshot, just the deltas
|
|
726
|
-
#
|
|
727
|
-
# {
|
|
728
|
-
# "type":"message",
|
|
729
|
-
# "topic":"/market/level2:BTC-USDT",
|
|
730
|
-
# "subject":"trade.l2update",
|
|
731
|
-
# "data":{
|
|
732
|
-
# "sequenceStart":1545896669105,
|
|
733
|
-
# "sequenceEnd":1545896669106,
|
|
734
|
-
# "symbol":"BTC-USDT",
|
|
735
|
-
# "changes": {
|
|
736
|
-
# "asks": [["6","1","1545896669105"]], # price, size, sequence
|
|
737
|
-
# "bids": [["4","1","1545896669106"]]
|
|
738
|
-
# }
|
|
739
|
-
# }
|
|
740
|
-
# }
|
|
741
|
-
#
|
|
742
|
-
# {
|
|
743
|
-
# "topic": "/spotMarket/level2Depth5:BTC-USDT",
|
|
744
|
-
# "type": "message",
|
|
745
|
-
# "data": {
|
|
746
|
-
# "asks": [
|
|
747
|
-
# [
|
|
748
|
-
# "42815.6",
|
|
749
|
-
# "1.24016245"
|
|
750
|
-
# ]
|
|
751
|
-
# ],
|
|
752
|
-
# "bids": [
|
|
753
|
-
# [
|
|
754
|
-
# "42815.5",
|
|
755
|
-
# "0.08652716"
|
|
756
|
-
# ]
|
|
757
|
-
# ],
|
|
758
|
-
# "timestamp": 1707204474018
|
|
759
|
-
# },
|
|
760
|
-
# "subject": "level2"
|
|
761
|
-
# }
|
|
762
|
-
#
|
|
763
|
-
data = self.safe_value(message, 'data')
|
|
764
|
-
subject = self.safe_string(message, 'subject')
|
|
765
|
-
topic = self.safe_string(message, 'topic')
|
|
766
|
-
topicParts = topic.split(':')
|
|
767
|
-
topicSymbol = self.safe_string(topicParts, 1)
|
|
768
|
-
topicChannel = self.safe_string(topicParts, 0)
|
|
769
|
-
marketId = self.safe_string(data, 'symbol', topicSymbol)
|
|
770
|
-
symbol = self.safe_symbol(marketId, None, '-')
|
|
771
|
-
messageHash = 'orderbook:' + symbol
|
|
772
|
-
# orderbook = self.safe_dict(self.orderbooks, symbol)
|
|
773
|
-
if subject == 'level2':
|
|
774
|
-
if not (symbol in self.orderbooks):
|
|
775
|
-
self.orderbooks[symbol] = self.order_book()
|
|
776
|
-
else:
|
|
777
|
-
orderbook = self.orderbooks[symbol]
|
|
778
|
-
orderbook.reset()
|
|
779
|
-
self.orderbooks[symbol]['symbol'] = symbol
|
|
780
|
-
else:
|
|
781
|
-
if not (symbol in self.orderbooks):
|
|
782
|
-
self.orderbooks[symbol] = self.order_book()
|
|
783
|
-
orderbook = self.orderbooks[symbol]
|
|
784
|
-
nonce = self.safe_integer(orderbook, 'nonce')
|
|
785
|
-
deltaEnd = self.safe_integer_2(data, 'sequenceEnd', 'timestamp')
|
|
786
|
-
if nonce is None:
|
|
787
|
-
cacheLength = len(orderbook.cache)
|
|
788
|
-
subscriptions = list(client.subscriptions.keys())
|
|
789
|
-
subscription = None
|
|
790
|
-
for i in range(0, len(subscriptions)):
|
|
791
|
-
key = subscriptions[i]
|
|
792
|
-
if (key.find(topicSymbol) >= 0) and (key.find(topicChannel) >= 0):
|
|
793
|
-
subscription = client.subscriptions[key]
|
|
794
|
-
break
|
|
795
|
-
limit = self.safe_integer(subscription, 'limit')
|
|
796
|
-
snapshotDelay = self.handle_option('watchOrderBook', 'snapshotDelay', 5)
|
|
797
|
-
if cacheLength == snapshotDelay:
|
|
798
|
-
self.spawn(self.load_order_book, client, messageHash, symbol, limit, {})
|
|
799
|
-
orderbook.cache.append(data)
|
|
800
|
-
return
|
|
801
|
-
elif nonce >= deltaEnd:
|
|
802
|
-
return
|
|
803
|
-
self.handle_delta(self.orderbooks[symbol], data)
|
|
804
|
-
client.resolve(self.orderbooks[symbol], messageHash)
|
|
805
|
-
|
|
806
|
-
def get_cache_index(self, orderbook, cache):
|
|
807
|
-
firstDelta = self.safe_value(cache, 0)
|
|
808
|
-
nonce = self.safe_integer(orderbook, 'nonce')
|
|
809
|
-
firstDeltaStart = self.safe_integer(firstDelta, 'sequenceStart')
|
|
810
|
-
if nonce < firstDeltaStart - 1:
|
|
811
|
-
return -1
|
|
812
|
-
for i in range(0, len(cache)):
|
|
813
|
-
delta = cache[i]
|
|
814
|
-
deltaStart = self.safe_integer(delta, 'sequenceStart')
|
|
815
|
-
deltaEnd = self.safe_integer(delta, 'sequenceEnd')
|
|
816
|
-
if (nonce >= deltaStart - 1) and (nonce < deltaEnd):
|
|
817
|
-
return i
|
|
818
|
-
return len(cache)
|
|
819
|
-
|
|
820
|
-
def handle_delta(self, orderbook, delta):
|
|
821
|
-
timestamp = self.safe_integer_2(delta, 'time', 'timestamp')
|
|
822
|
-
orderbook['nonce'] = self.safe_integer(delta, 'sequenceEnd', timestamp)
|
|
823
|
-
orderbook['timestamp'] = timestamp
|
|
824
|
-
orderbook['datetime'] = self.iso8601(timestamp)
|
|
825
|
-
changes = self.safe_value(delta, 'changes', delta)
|
|
826
|
-
bids = self.safe_value(changes, 'bids', [])
|
|
827
|
-
asks = self.safe_value(changes, 'asks', [])
|
|
828
|
-
storedBids = orderbook['bids']
|
|
829
|
-
storedAsks = orderbook['asks']
|
|
830
|
-
self.handle_bid_asks(storedBids, bids)
|
|
831
|
-
self.handle_bid_asks(storedAsks, asks)
|
|
832
|
-
|
|
833
|
-
def handle_bid_asks(self, bookSide, bidAsks):
|
|
834
|
-
for i in range(0, len(bidAsks)):
|
|
835
|
-
bidAsk = self.parse_bid_ask(bidAsks[i])
|
|
836
|
-
bookSide.storeArray(bidAsk)
|
|
837
|
-
|
|
838
|
-
def handle_order_book_subscription(self, client: Client, message, subscription):
|
|
839
|
-
limit = self.safe_integer(subscription, 'limit')
|
|
840
|
-
symbols = self.safe_value(subscription, 'symbols')
|
|
841
|
-
if symbols is None:
|
|
842
|
-
symbol = self.safe_string(subscription, 'symbol')
|
|
843
|
-
self.orderbooks[symbol] = self.order_book({}, limit)
|
|
844
|
-
else:
|
|
845
|
-
for i in range(0, len(symbols)):
|
|
846
|
-
symbol = symbols[i]
|
|
847
|
-
self.orderbooks[symbol] = self.order_book({}, limit)
|
|
848
|
-
# moved snapshot initialization to handleOrderBook to fix
|
|
849
|
-
# https://github.com/ccxt/ccxt/issues/6820
|
|
850
|
-
# the general idea is to fetch the snapshot after the first delta
|
|
851
|
-
# but not before, because otherwise we cannot synchronize the feed
|
|
852
|
-
|
|
853
|
-
def handle_subscription_status(self, client: Client, message):
|
|
854
|
-
#
|
|
855
|
-
# {
|
|
856
|
-
# "id": "1578090438322",
|
|
857
|
-
# "type": "ack"
|
|
858
|
-
# }
|
|
859
|
-
#
|
|
860
|
-
id = self.safe_string(message, 'id')
|
|
861
|
-
if not (id in client.subscriptions):
|
|
862
|
-
return
|
|
863
|
-
subscriptionHash = self.safe_string(client.subscriptions, id)
|
|
864
|
-
subscription = self.safe_value(client.subscriptions, subscriptionHash)
|
|
865
|
-
del client.subscriptions[id]
|
|
866
|
-
method = self.safe_value(subscription, 'method')
|
|
867
|
-
if method is not None:
|
|
868
|
-
method(client, message, subscription)
|
|
869
|
-
isUnSub = self.safe_bool(subscription, 'unsubscribe', False)
|
|
870
|
-
if isUnSub:
|
|
871
|
-
messageHashes = self.safe_list(subscription, 'messageHashes', [])
|
|
872
|
-
subMessageHashes = self.safe_list(subscription, 'subMessageHashes', [])
|
|
873
|
-
for i in range(0, len(messageHashes)):
|
|
874
|
-
messageHash = messageHashes[i]
|
|
875
|
-
subHash = subMessageHashes[i]
|
|
876
|
-
self.clean_unsubscription(client, subHash, messageHash)
|
|
877
|
-
self.clean_cache(subscription)
|
|
878
|
-
|
|
879
|
-
def handle_system_status(self, client: Client, message):
|
|
880
|
-
#
|
|
881
|
-
# todo: answer the question whether handleSystemStatus should be renamed
|
|
882
|
-
# and unified for any usage pattern that
|
|
883
|
-
# involves system status and maintenance updates
|
|
884
|
-
#
|
|
885
|
-
# {
|
|
886
|
-
# "id": "1578090234088", # connectId
|
|
887
|
-
# "type": "welcome",
|
|
888
|
-
# }
|
|
889
|
-
#
|
|
890
|
-
return message
|
|
891
|
-
|
|
892
|
-
async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
|
893
|
-
"""
|
|
894
|
-
watches information on multiple orders made by the user
|
|
895
|
-
|
|
896
|
-
https://www.kucoin.com/docs/websocket/spot-trading/private-channels/private-order-change
|
|
897
|
-
https://www.kucoin.com/docs/websocket/spot-trading/private-channels/stop-order-event
|
|
898
|
-
|
|
899
|
-
:param str symbol: unified market symbol of the market orders were made in
|
|
900
|
-
:param int [since]: the earliest time in ms to fetch orders for
|
|
901
|
-
:param int [limit]: the maximum number of order structures to retrieve
|
|
902
|
-
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
903
|
-
:param boolean [params.trigger]: trigger orders are watched if True
|
|
904
|
-
:returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
905
|
-
"""
|
|
906
|
-
await self.load_markets()
|
|
907
|
-
trigger = self.safe_value_2(params, 'stop', 'trigger')
|
|
908
|
-
params = self.omit(params, ['stop', 'trigger'])
|
|
909
|
-
url = await self.negotiate(True)
|
|
910
|
-
topic = '/spotMarket/advancedOrders' if trigger else '/spotMarket/tradeOrders'
|
|
911
|
-
request: dict = {
|
|
912
|
-
'privateChannel': True,
|
|
913
|
-
}
|
|
914
|
-
messageHash = 'orders'
|
|
915
|
-
if symbol is not None:
|
|
916
|
-
market = self.market(symbol)
|
|
917
|
-
symbol = market['symbol']
|
|
918
|
-
messageHash = messageHash + ':' + symbol
|
|
919
|
-
orders = await self.subscribe(url, messageHash, topic, self.extend(request, params))
|
|
920
|
-
if self.newUpdates:
|
|
921
|
-
limit = orders.getLimit(symbol, limit)
|
|
922
|
-
return self.filter_by_symbol_since_limit(orders, symbol, since, limit, True)
|
|
923
|
-
|
|
924
|
-
def parse_ws_order_status(self, status):
|
|
925
|
-
statuses: dict = {
|
|
926
|
-
'open': 'open',
|
|
927
|
-
'filled': 'closed',
|
|
928
|
-
'match': 'open',
|
|
929
|
-
'update': 'open',
|
|
930
|
-
'canceled': 'canceled',
|
|
931
|
-
'cancel': 'canceled',
|
|
932
|
-
'TRIGGERED': 'triggered',
|
|
933
|
-
}
|
|
934
|
-
return self.safe_string(statuses, status, status)
|
|
935
|
-
|
|
936
|
-
def parse_ws_order(self, order, market=None):
|
|
937
|
-
#
|
|
938
|
-
# /spotMarket/tradeOrders
|
|
939
|
-
#
|
|
940
|
-
# {
|
|
941
|
-
# "symbol": "XCAD-USDT",
|
|
942
|
-
# "orderType": "limit",
|
|
943
|
-
# "side": "buy",
|
|
944
|
-
# "orderId": "6249167327218b000135e749",
|
|
945
|
-
# "type": "canceled",
|
|
946
|
-
# "orderTime": 1648957043065280224,
|
|
947
|
-
# "size": "100.452",
|
|
948
|
-
# "filledSize": "0",
|
|
949
|
-
# "price": "2.9635",
|
|
950
|
-
# "clientOid": "buy-XCAD-USDT-1648957043010159",
|
|
951
|
-
# "remainSize": "0",
|
|
952
|
-
# "status": "done",
|
|
953
|
-
# "ts": 1648957054031001037
|
|
954
|
-
# }
|
|
955
|
-
#
|
|
956
|
-
# /spotMarket/advancedOrders
|
|
957
|
-
#
|
|
958
|
-
# {
|
|
959
|
-
# "createdAt": 1589789942337,
|
|
960
|
-
# "orderId": "5ec244f6a8a75e0009958237",
|
|
961
|
-
# "orderPrice": "0.00062",
|
|
962
|
-
# "orderType": "stop",
|
|
963
|
-
# "side": "sell",
|
|
964
|
-
# "size": "1",
|
|
965
|
-
# "stop": "entry",
|
|
966
|
-
# "stopPrice": "0.00062",
|
|
967
|
-
# "symbol": "KCS-BTC",
|
|
968
|
-
# "tradeType": "TRADE",
|
|
969
|
-
# "triggerSuccess": True,
|
|
970
|
-
# "ts": 1589790121382281286,
|
|
971
|
-
# "type": "triggered"
|
|
972
|
-
# }
|
|
973
|
-
#
|
|
974
|
-
rawType = self.safe_string(order, 'type')
|
|
975
|
-
status = self.parse_ws_order_status(rawType)
|
|
976
|
-
timestamp = self.safe_integer_2(order, 'orderTime', 'createdAt')
|
|
977
|
-
marketId = self.safe_string(order, 'symbol')
|
|
978
|
-
market = self.safe_market(marketId, market)
|
|
979
|
-
triggerPrice = self.safe_string(order, 'stopPrice')
|
|
980
|
-
triggerSuccess = self.safe_value(order, 'triggerSuccess')
|
|
981
|
-
triggerFail = (triggerSuccess is not True) and (triggerSuccess is not None) # TODO: updated to triggerSuccess == False once transpiler transpiles it correctly
|
|
982
|
-
if (status == 'triggered') and triggerFail:
|
|
983
|
-
status = 'canceled'
|
|
984
|
-
return self.safe_order({
|
|
985
|
-
'info': order,
|
|
986
|
-
'symbol': market['symbol'],
|
|
987
|
-
'id': self.safe_string(order, 'orderId'),
|
|
988
|
-
'clientOrderId': self.safe_string(order, 'clientOid'),
|
|
989
|
-
'timestamp': timestamp,
|
|
990
|
-
'datetime': self.iso8601(timestamp),
|
|
991
|
-
'lastTradeTimestamp': None,
|
|
992
|
-
'type': self.safe_string_lower(order, 'orderType'),
|
|
993
|
-
'timeInForce': None,
|
|
994
|
-
'postOnly': None,
|
|
995
|
-
'side': self.safe_string_lower(order, 'side'),
|
|
996
|
-
'price': self.safe_string_2(order, 'price', 'orderPrice'),
|
|
997
|
-
'stopPrice': triggerPrice,
|
|
998
|
-
'triggerPrice': triggerPrice,
|
|
999
|
-
'amount': self.safe_string(order, 'size'),
|
|
1000
|
-
'cost': None,
|
|
1001
|
-
'average': None,
|
|
1002
|
-
'filled': self.safe_string(order, 'filledSize'),
|
|
1003
|
-
'remaining': None,
|
|
1004
|
-
'status': status,
|
|
1005
|
-
'fee': None,
|
|
1006
|
-
'trades': None,
|
|
1007
|
-
}, market)
|
|
1008
|
-
|
|
1009
|
-
def handle_order(self, client: Client, message):
|
|
1010
|
-
#
|
|
1011
|
-
# Trigger Orders
|
|
1012
|
-
#
|
|
1013
|
-
# {
|
|
1014
|
-
# "createdAt": 1692745706437,
|
|
1015
|
-
# "error": "Balance insufficient!", # not always there
|
|
1016
|
-
# "orderId": "vs86kp757vlda6ni003qs70v",
|
|
1017
|
-
# "orderPrice": "0.26",
|
|
1018
|
-
# "orderType": "stop",
|
|
1019
|
-
# "side": "sell",
|
|
1020
|
-
# "size": "5",
|
|
1021
|
-
# "stop": "loss",
|
|
1022
|
-
# "stopPrice": "0.26",
|
|
1023
|
-
# "symbol": "ADA-USDT",
|
|
1024
|
-
# "tradeType": "TRADE",
|
|
1025
|
-
# "triggerSuccess": False, # not always there
|
|
1026
|
-
# "ts": "1692745706442929298",
|
|
1027
|
-
# "type": "open"
|
|
1028
|
-
# }
|
|
1029
|
-
#
|
|
1030
|
-
messageHash = 'orders'
|
|
1031
|
-
data = self.safe_value(message, 'data')
|
|
1032
|
-
tradeId = self.safe_string(data, 'tradeId')
|
|
1033
|
-
if tradeId is not None:
|
|
1034
|
-
self.handle_my_trade(client, message)
|
|
1035
|
-
parsed = self.parse_ws_order(data)
|
|
1036
|
-
symbol = self.safe_string(parsed, 'symbol')
|
|
1037
|
-
orderId = self.safe_string(parsed, 'id')
|
|
1038
|
-
triggerPrice = self.safe_value(parsed, 'triggerPrice')
|
|
1039
|
-
isTriggerOrder = (triggerPrice is not None)
|
|
1040
|
-
if self.orders is None:
|
|
1041
|
-
limit = self.safe_integer(self.options, 'ordersLimit', 1000)
|
|
1042
|
-
self.orders = ArrayCacheBySymbolById(limit)
|
|
1043
|
-
self.triggerOrders = ArrayCacheBySymbolById(limit)
|
|
1044
|
-
cachedOrders = self.triggerOrders if isTriggerOrder else self.orders
|
|
1045
|
-
orders = self.safe_value(cachedOrders.hashmap, symbol, {})
|
|
1046
|
-
order = self.safe_value(orders, orderId)
|
|
1047
|
-
if order is not None:
|
|
1048
|
-
# todo add others to calculate average etc
|
|
1049
|
-
if order['status'] == 'closed':
|
|
1050
|
-
parsed['status'] = 'closed'
|
|
1051
|
-
cachedOrders.append(parsed)
|
|
1052
|
-
client.resolve(cachedOrders, messageHash)
|
|
1053
|
-
symbolSpecificMessageHash = messageHash + ':' + symbol
|
|
1054
|
-
client.resolve(cachedOrders, symbolSpecificMessageHash)
|
|
1055
|
-
|
|
1056
|
-
async def watch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
|
1057
|
-
"""
|
|
1058
|
-
watches information on multiple trades made by the user
|
|
1059
|
-
|
|
1060
|
-
https://www.kucoin.com/docs/websocket/spot-trading/private-channels/private-order-change
|
|
1061
|
-
|
|
1062
|
-
:param str symbol: unified market symbol of the market trades were made in
|
|
1063
|
-
:param int [since]: the earliest time in ms to fetch trades for
|
|
1064
|
-
:param int [limit]: the maximum number of trade structures to retrieve
|
|
1065
|
-
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1066
|
-
:param str [params.method]: '/spotMarket/tradeOrders' or '/spot/tradeFills' default is '/spotMarket/tradeOrders'
|
|
1067
|
-
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
|
|
1068
|
-
"""
|
|
1069
|
-
await self.load_markets()
|
|
1070
|
-
url = await self.negotiate(True)
|
|
1071
|
-
topic: Str = None
|
|
1072
|
-
topic, params = self.handle_option_and_params(params, 'watchMyTrades', 'method', '/spotMarket/tradeOrders')
|
|
1073
|
-
request: dict = {
|
|
1074
|
-
'privateChannel': True,
|
|
1075
|
-
}
|
|
1076
|
-
messageHash = 'myTrades'
|
|
1077
|
-
if symbol is not None:
|
|
1078
|
-
market = self.market(symbol)
|
|
1079
|
-
symbol = market['symbol']
|
|
1080
|
-
messageHash = messageHash + ':' + market['symbol']
|
|
1081
|
-
trades = await self.subscribe(url, messageHash, topic, self.extend(request, params))
|
|
1082
|
-
if self.newUpdates:
|
|
1083
|
-
limit = trades.getLimit(symbol, limit)
|
|
1084
|
-
return self.filter_by_symbol_since_limit(trades, symbol, since, limit, True)
|
|
1085
|
-
|
|
1086
|
-
def handle_my_trade(self, client: Client, message):
|
|
1087
|
-
#
|
|
1088
|
-
# {
|
|
1089
|
-
# "type": "message",
|
|
1090
|
-
# "topic": "/spotMarket/tradeOrders",
|
|
1091
|
-
# "subject": "orderChange",
|
|
1092
|
-
# "channelType": "private",
|
|
1093
|
-
# "data": {
|
|
1094
|
-
# "symbol": "KCS-USDT",
|
|
1095
|
-
# "orderType": "limit",
|
|
1096
|
-
# "side": "sell",
|
|
1097
|
-
# "orderId": "5efab07953bdea00089965fa",
|
|
1098
|
-
# "liquidity": "taker",
|
|
1099
|
-
# "type": "match",
|
|
1100
|
-
# "feeType": "takerFee",
|
|
1101
|
-
# "orderTime": 1670329987026,
|
|
1102
|
-
# "size": "0.1",
|
|
1103
|
-
# "filledSize": "0.1",
|
|
1104
|
-
# "price": "0.938",
|
|
1105
|
-
# "matchPrice": "0.96738",
|
|
1106
|
-
# "matchSize": "0.1",
|
|
1107
|
-
# "tradeId": "5efab07a4ee4c7000a82d6d9",
|
|
1108
|
-
# "clientOid": "1593487481000313",
|
|
1109
|
-
# "remainSize": "0",
|
|
1110
|
-
# "status": "match",
|
|
1111
|
-
# "ts": 1670329987311000000
|
|
1112
|
-
# }
|
|
1113
|
-
# }
|
|
1114
|
-
#
|
|
1115
|
-
if self.myTrades is None:
|
|
1116
|
-
limit = self.safe_integer(self.options, 'tradesLimit', 1000)
|
|
1117
|
-
self.myTrades = ArrayCacheBySymbolById(limit)
|
|
1118
|
-
data = self.safe_dict(message, 'data')
|
|
1119
|
-
parsed = self.parse_ws_trade(data)
|
|
1120
|
-
myTrades = self.myTrades
|
|
1121
|
-
myTrades.append(parsed)
|
|
1122
|
-
messageHash = 'myTrades'
|
|
1123
|
-
client.resolve(self.myTrades, messageHash)
|
|
1124
|
-
symbolSpecificMessageHash = messageHash + ':' + parsed['symbol']
|
|
1125
|
-
client.resolve(self.myTrades, symbolSpecificMessageHash)
|
|
1126
|
-
|
|
1127
|
-
def parse_ws_trade(self, trade, market=None):
|
|
1128
|
-
#
|
|
1129
|
-
# /spotMarket/tradeOrders
|
|
1130
|
-
#
|
|
1131
|
-
# {
|
|
1132
|
-
# "symbol": "KCS-USDT",
|
|
1133
|
-
# "orderType": "limit",
|
|
1134
|
-
# "side": "sell",
|
|
1135
|
-
# "orderId": "5efab07953bdea00089965fa",
|
|
1136
|
-
# "liquidity": "taker",
|
|
1137
|
-
# "type": "match",
|
|
1138
|
-
# "feeType": "takerFee",
|
|
1139
|
-
# "orderTime": 1670329987026,
|
|
1140
|
-
# "size": "0.1",
|
|
1141
|
-
# "filledSize": "0.1",
|
|
1142
|
-
# "price": "0.938",
|
|
1143
|
-
# "matchPrice": "0.96738",
|
|
1144
|
-
# "matchSize": "0.1",
|
|
1145
|
-
# "tradeId": "5efab07a4ee4c7000a82d6d9",
|
|
1146
|
-
# "clientOid": "1593487481000313",
|
|
1147
|
-
# "remainSize": "0",
|
|
1148
|
-
# "status": "match",
|
|
1149
|
-
# "ts": 1670329987311000000
|
|
1150
|
-
# }
|
|
1151
|
-
#
|
|
1152
|
-
# /spot/tradeFills
|
|
1153
|
-
#
|
|
1154
|
-
# {
|
|
1155
|
-
# "fee": 0.00262148,
|
|
1156
|
-
# "feeCurrency": "USDT",
|
|
1157
|
-
# "feeRate": 0.001,
|
|
1158
|
-
# "orderId": "62417436b29df8000183df2f",
|
|
1159
|
-
# "orderType": "market",
|
|
1160
|
-
# "price": 131.074,
|
|
1161
|
-
# "side": "sell",
|
|
1162
|
-
# "size": 0.02,
|
|
1163
|
-
# "symbol": "LTC-USDT",
|
|
1164
|
-
# "time": "1648456758734571745",
|
|
1165
|
-
# "tradeId": "624174362e113d2f467b3043"
|
|
1166
|
-
# }
|
|
1167
|
-
#
|
|
1168
|
-
marketId = self.safe_string(trade, 'symbol')
|
|
1169
|
-
market = self.safe_market(marketId, market, '-')
|
|
1170
|
-
symbol = market['symbol']
|
|
1171
|
-
type = self.safe_string(trade, 'orderType')
|
|
1172
|
-
side = self.safe_string(trade, 'side')
|
|
1173
|
-
tradeId = self.safe_string(trade, 'tradeId')
|
|
1174
|
-
price = self.safe_string(trade, 'matchPrice')
|
|
1175
|
-
amount = self.safe_string(trade, 'matchSize')
|
|
1176
|
-
if price is None:
|
|
1177
|
-
# /spot/tradeFills
|
|
1178
|
-
price = self.safe_string(trade, 'price')
|
|
1179
|
-
amount = self.safe_string(trade, 'size')
|
|
1180
|
-
order = self.safe_string(trade, 'orderId')
|
|
1181
|
-
timestamp = self.safe_integer_product_2(trade, 'ts', 'time', 0.000001)
|
|
1182
|
-
feeCurrency = market['quote']
|
|
1183
|
-
feeRate = self.safe_string(trade, 'feeRate')
|
|
1184
|
-
feeCost = self.safe_string(trade, 'fee')
|
|
1185
|
-
return self.safe_trade({
|
|
1186
|
-
'info': trade,
|
|
1187
|
-
'timestamp': timestamp,
|
|
1188
|
-
'datetime': self.iso8601(timestamp),
|
|
1189
|
-
'symbol': symbol,
|
|
1190
|
-
'id': tradeId,
|
|
1191
|
-
'order': order,
|
|
1192
|
-
'type': type,
|
|
1193
|
-
'takerOrMaker': self.safe_string(trade, 'liquidity'),
|
|
1194
|
-
'side': side,
|
|
1195
|
-
'price': price,
|
|
1196
|
-
'amount': amount,
|
|
1197
|
-
'cost': None,
|
|
1198
|
-
'fee': {
|
|
1199
|
-
'cost': feeCost,
|
|
1200
|
-
'rate': feeRate,
|
|
1201
|
-
'currency': feeCurrency,
|
|
1202
|
-
},
|
|
1203
|
-
}, market)
|
|
1204
|
-
|
|
1205
|
-
async def watch_balance(self, params={}) -> Balances:
|
|
1206
|
-
"""
|
|
1207
|
-
watch balance and get the amount of funds available for trading or funds locked in orders
|
|
1208
|
-
|
|
1209
|
-
https://www.kucoin.com/docs/websocket/spot-trading/private-channels/account-balance-change
|
|
1210
|
-
|
|
1211
|
-
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1212
|
-
:returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
|
|
1213
|
-
"""
|
|
1214
|
-
await self.load_markets()
|
|
1215
|
-
url = await self.negotiate(True)
|
|
1216
|
-
topic = '/account/balance'
|
|
1217
|
-
request: dict = {
|
|
1218
|
-
'privateChannel': True,
|
|
1219
|
-
}
|
|
1220
|
-
messageHash = 'balance'
|
|
1221
|
-
return await self.subscribe(url, messageHash, topic, self.extend(request, params))
|
|
1222
|
-
|
|
1223
|
-
def handle_balance(self, client: Client, message):
|
|
1224
|
-
#
|
|
1225
|
-
# {
|
|
1226
|
-
# "id":"6217a451294b030001e3a26a",
|
|
1227
|
-
# "type":"message",
|
|
1228
|
-
# "topic":"/account/balance",
|
|
1229
|
-
# "userId":"6217707c52f97f00012a67db",
|
|
1230
|
-
# "channelType":"private",
|
|
1231
|
-
# "subject":"account.balance",
|
|
1232
|
-
# "data":{
|
|
1233
|
-
# "accountId":"62177fe67810720001db2f18",
|
|
1234
|
-
# "available":"89",
|
|
1235
|
-
# "availableChange":"-30",
|
|
1236
|
-
# "currency":"USDT",
|
|
1237
|
-
# "hold":"0",
|
|
1238
|
-
# "holdChange":"0",
|
|
1239
|
-
# "relationContext":{
|
|
1240
|
-
# },
|
|
1241
|
-
# "relationEvent":"main.transfer",
|
|
1242
|
-
# "relationEventId":"6217a451294b030001e3a26a",
|
|
1243
|
-
# "time":"1645716561816",
|
|
1244
|
-
# "total":"89"
|
|
1245
|
-
# }
|
|
1246
|
-
#
|
|
1247
|
-
data = self.safe_value(message, 'data', {})
|
|
1248
|
-
messageHash = 'balance'
|
|
1249
|
-
currencyId = self.safe_string(data, 'currency')
|
|
1250
|
-
relationEvent = self.safe_string(data, 'relationEvent')
|
|
1251
|
-
requestAccountType = None
|
|
1252
|
-
if relationEvent is not None:
|
|
1253
|
-
relationEventParts = relationEvent.split('.')
|
|
1254
|
-
requestAccountType = self.safe_string(relationEventParts, 0)
|
|
1255
|
-
selectedType = self.safe_string_2(self.options, 'watchBalance', 'defaultType', 'trade') # trade, main, margin or other
|
|
1256
|
-
accountsByType = self.safe_value(self.options, 'accountsByType')
|
|
1257
|
-
uniformType = self.safe_string(accountsByType, requestAccountType, 'trade')
|
|
1258
|
-
if not (uniformType in self.balance):
|
|
1259
|
-
self.balance[uniformType] = {}
|
|
1260
|
-
self.balance[uniformType]['info'] = data
|
|
1261
|
-
timestamp = self.safe_integer(data, 'time')
|
|
1262
|
-
self.balance[uniformType]['timestamp'] = timestamp
|
|
1263
|
-
self.balance[uniformType]['datetime'] = self.iso8601(timestamp)
|
|
1264
|
-
code = self.safe_currency_code(currencyId)
|
|
1265
|
-
account = self.account()
|
|
1266
|
-
account['free'] = self.safe_string(data, 'available')
|
|
1267
|
-
account['used'] = self.safe_string(data, 'hold')
|
|
1268
|
-
account['total'] = self.safe_string(data, 'total')
|
|
1269
|
-
self.balance[uniformType][code] = account
|
|
1270
|
-
self.balance[uniformType] = self.safe_balance(self.balance[uniformType])
|
|
1271
|
-
if uniformType == selectedType:
|
|
1272
|
-
client.resolve(self.balance[uniformType], messageHash)
|
|
1273
|
-
|
|
1274
|
-
def handle_subject(self, client: Client, message):
|
|
1275
|
-
#
|
|
1276
|
-
# {
|
|
1277
|
-
# "type":"message",
|
|
1278
|
-
# "topic":"/market/level2:BTC-USDT",
|
|
1279
|
-
# "subject":"trade.l2update",
|
|
1280
|
-
# "data":{
|
|
1281
|
-
# "sequenceStart":1545896669105,
|
|
1282
|
-
# "sequenceEnd":1545896669106,
|
|
1283
|
-
# "symbol":"BTC-USDT",
|
|
1284
|
-
# "changes": {
|
|
1285
|
-
# "asks": [["6","1","1545896669105"]], # price, size, sequence
|
|
1286
|
-
# "bids": [["4","1","1545896669106"]]
|
|
1287
|
-
# }
|
|
1288
|
-
# }
|
|
1289
|
-
# }
|
|
1290
|
-
#
|
|
1291
|
-
topic = self.safe_string(message, 'topic')
|
|
1292
|
-
if topic == '/market/ticker:all':
|
|
1293
|
-
self.handle_ticker(client, message)
|
|
1294
|
-
return
|
|
1295
|
-
subject = self.safe_string(message, 'subject')
|
|
1296
|
-
methods: dict = {
|
|
1297
|
-
'level1': self.handle_bid_ask,
|
|
1298
|
-
'level2': self.handle_order_book,
|
|
1299
|
-
'trade.l2update': self.handle_order_book,
|
|
1300
|
-
'trade.ticker': self.handle_ticker,
|
|
1301
|
-
'trade.snapshot': self.handle_ticker,
|
|
1302
|
-
'trade.l3match': self.handle_trade,
|
|
1303
|
-
'trade.candles.update': self.handle_ohlcv,
|
|
1304
|
-
'account.balance': self.handle_balance,
|
|
1305
|
-
'orderChange': self.handle_order,
|
|
1306
|
-
'stopOrder': self.handle_order,
|
|
1307
|
-
'/spot/tradeFills': self.handle_my_trade,
|
|
1308
|
-
}
|
|
1309
|
-
method = self.safe_value(methods, subject)
|
|
1310
|
-
if method is not None:
|
|
1311
|
-
method(client, message)
|
|
1312
|
-
|
|
1313
|
-
def ping(self, client: Client):
|
|
1314
|
-
# kucoin does not support built-in ws protocol-level ping-pong
|
|
1315
|
-
# instead it requires a custom json-based text ping-pong
|
|
1316
|
-
# https://docs.kucoin.com/#ping
|
|
1317
|
-
id = str(self.request_id())
|
|
1318
|
-
return {
|
|
1319
|
-
'id': id,
|
|
1320
|
-
'type': 'ping',
|
|
1321
|
-
}
|
|
1322
|
-
|
|
1323
|
-
def handle_pong(self, client: Client, message):
|
|
1324
|
-
client.lastPong = self.milliseconds()
|
|
1325
|
-
# https://docs.kucoin.com/#ping
|
|
1326
|
-
|
|
1327
|
-
def handle_error_message(self, client: Client, message):
|
|
1328
|
-
#
|
|
1329
|
-
# {
|
|
1330
|
-
# "id": "1",
|
|
1331
|
-
# "type": "error",
|
|
1332
|
-
# "code": 415,
|
|
1333
|
-
# "data": "type is not supported"
|
|
1334
|
-
# }
|
|
1335
|
-
#
|
|
1336
|
-
data = self.safe_string(message, 'data', '')
|
|
1337
|
-
if data == 'token is expired':
|
|
1338
|
-
type = 'public'
|
|
1339
|
-
if client.url.find('connectId=private') >= 0:
|
|
1340
|
-
type = 'private'
|
|
1341
|
-
self.options['urls'][type] = None
|
|
1342
|
-
self.handle_errors(None, None, client.url, None, None, data, message, None, None)
|
|
1343
|
-
|
|
1344
|
-
def handle_message(self, client: Client, message):
|
|
1345
|
-
type = self.safe_string(message, 'type')
|
|
1346
|
-
methods: dict = {
|
|
1347
|
-
# 'heartbeat': self.handleHeartbeat,
|
|
1348
|
-
'welcome': self.handle_system_status,
|
|
1349
|
-
'ack': self.handle_subscription_status,
|
|
1350
|
-
'message': self.handle_subject,
|
|
1351
|
-
'pong': self.handle_pong,
|
|
1352
|
-
'error': self.handle_error_message,
|
|
1353
|
-
}
|
|
1354
|
-
method = self.safe_value(methods, type)
|
|
1355
|
-
if method is not None:
|
|
1356
|
-
method(client, message)
|