bitmart 0.0.12__py3-none-any.whl → 0.0.14__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 bitmart might be problematic. Click here for more details.

Files changed (289) hide show
  1. bitmart/__init__.py +7 -0
  2. bitmart/ccxt/__init__.py +101 -0
  3. bitmart/ccxt/abstract/bitmart.py +113 -0
  4. bitmart/ccxt/async_support/__init__.py +80 -0
  5. bitmart/ccxt/async_support/base/__init__.py +1 -0
  6. bitmart/ccxt/async_support/base/exchange.py +2100 -0
  7. bitmart/ccxt/async_support/base/throttler.py +50 -0
  8. bitmart/ccxt/async_support/base/ws/__init__.py +38 -0
  9. bitmart/ccxt/async_support/base/ws/aiohttp_client.py +147 -0
  10. bitmart/ccxt/async_support/base/ws/cache.py +213 -0
  11. bitmart/ccxt/async_support/base/ws/client.py +214 -0
  12. bitmart/ccxt/async_support/base/ws/fast_client.py +97 -0
  13. bitmart/ccxt/async_support/base/ws/functions.py +59 -0
  14. bitmart/ccxt/async_support/base/ws/future.py +69 -0
  15. bitmart/ccxt/async_support/base/ws/order_book.py +78 -0
  16. bitmart/ccxt/async_support/base/ws/order_book_side.py +174 -0
  17. bitmart/ccxt/async_support/bitmart.py +5266 -0
  18. bitmart/ccxt/base/__init__.py +27 -0
  19. bitmart/ccxt/base/decimal_to_precision.py +174 -0
  20. bitmart/ccxt/base/errors.py +267 -0
  21. bitmart/ccxt/base/exchange.py +6769 -0
  22. bitmart/ccxt/base/precise.py +297 -0
  23. bitmart/ccxt/base/types.py +577 -0
  24. bitmart/ccxt/bitmart.py +5266 -0
  25. bitmart/ccxt/pro/__init__.py +21 -0
  26. bitmart/ccxt/pro/bitmart.py +1565 -0
  27. bitmart/ccxt/static_dependencies/README.md +1 -0
  28. bitmart/ccxt/static_dependencies/__init__.py +1 -0
  29. bitmart/ccxt/static_dependencies/ecdsa/__init__.py +14 -0
  30. bitmart/ccxt/static_dependencies/ecdsa/_version.py +520 -0
  31. bitmart/ccxt/static_dependencies/ecdsa/curves.py +56 -0
  32. bitmart/ccxt/static_dependencies/ecdsa/der.py +221 -0
  33. bitmart/ccxt/static_dependencies/ecdsa/ecdsa.py +310 -0
  34. bitmart/ccxt/static_dependencies/ecdsa/ellipticcurve.py +197 -0
  35. bitmart/ccxt/static_dependencies/ecdsa/keys.py +332 -0
  36. bitmart/ccxt/static_dependencies/ecdsa/numbertheory.py +531 -0
  37. bitmart/ccxt/static_dependencies/ecdsa/rfc6979.py +100 -0
  38. bitmart/ccxt/static_dependencies/ecdsa/util.py +266 -0
  39. bitmart/ccxt/static_dependencies/ethereum/__init__.py +7 -0
  40. bitmart/ccxt/static_dependencies/ethereum/abi/__init__.py +16 -0
  41. bitmart/ccxt/static_dependencies/ethereum/abi/abi.py +19 -0
  42. bitmart/ccxt/static_dependencies/ethereum/abi/base.py +152 -0
  43. bitmart/ccxt/static_dependencies/ethereum/abi/codec.py +217 -0
  44. bitmart/ccxt/static_dependencies/ethereum/abi/constants.py +3 -0
  45. bitmart/ccxt/static_dependencies/ethereum/abi/decoding.py +565 -0
  46. bitmart/ccxt/static_dependencies/ethereum/abi/encoding.py +720 -0
  47. bitmart/ccxt/static_dependencies/ethereum/abi/exceptions.py +139 -0
  48. bitmart/ccxt/static_dependencies/ethereum/abi/grammar.py +443 -0
  49. bitmart/ccxt/static_dependencies/ethereum/abi/packed.py +13 -0
  50. bitmart/ccxt/static_dependencies/ethereum/abi/py.typed +0 -0
  51. bitmart/ccxt/static_dependencies/ethereum/abi/registry.py +643 -0
  52. bitmart/ccxt/static_dependencies/ethereum/abi/tools/__init__.py +3 -0
  53. bitmart/ccxt/static_dependencies/ethereum/abi/tools/_strategies.py +230 -0
  54. bitmart/ccxt/static_dependencies/ethereum/abi/utils/__init__.py +0 -0
  55. bitmart/ccxt/static_dependencies/ethereum/abi/utils/numeric.py +83 -0
  56. bitmart/ccxt/static_dependencies/ethereum/abi/utils/padding.py +27 -0
  57. bitmart/ccxt/static_dependencies/ethereum/abi/utils/string.py +19 -0
  58. bitmart/ccxt/static_dependencies/ethereum/account/__init__.py +3 -0
  59. bitmart/ccxt/static_dependencies/ethereum/account/encode_typed_data/__init__.py +4 -0
  60. bitmart/ccxt/static_dependencies/ethereum/account/encode_typed_data/encoding_and_hashing.py +239 -0
  61. bitmart/ccxt/static_dependencies/ethereum/account/encode_typed_data/helpers.py +40 -0
  62. bitmart/ccxt/static_dependencies/ethereum/account/messages.py +263 -0
  63. bitmart/ccxt/static_dependencies/ethereum/account/py.typed +0 -0
  64. bitmart/ccxt/static_dependencies/ethereum/hexbytes/__init__.py +5 -0
  65. bitmart/ccxt/static_dependencies/ethereum/hexbytes/_utils.py +54 -0
  66. bitmart/ccxt/static_dependencies/ethereum/hexbytes/main.py +65 -0
  67. bitmart/ccxt/static_dependencies/ethereum/hexbytes/py.typed +0 -0
  68. bitmart/ccxt/static_dependencies/ethereum/typing/__init__.py +63 -0
  69. bitmart/ccxt/static_dependencies/ethereum/typing/abi.py +6 -0
  70. bitmart/ccxt/static_dependencies/ethereum/typing/bls.py +7 -0
  71. bitmart/ccxt/static_dependencies/ethereum/typing/discovery.py +5 -0
  72. bitmart/ccxt/static_dependencies/ethereum/typing/encoding.py +7 -0
  73. bitmart/ccxt/static_dependencies/ethereum/typing/enums.py +17 -0
  74. bitmart/ccxt/static_dependencies/ethereum/typing/ethpm.py +9 -0
  75. bitmart/ccxt/static_dependencies/ethereum/typing/evm.py +20 -0
  76. bitmart/ccxt/static_dependencies/ethereum/typing/networks.py +1122 -0
  77. bitmart/ccxt/static_dependencies/ethereum/typing/py.typed +0 -0
  78. bitmart/ccxt/static_dependencies/ethereum/utils/__init__.py +115 -0
  79. bitmart/ccxt/static_dependencies/ethereum/utils/abi.py +72 -0
  80. bitmart/ccxt/static_dependencies/ethereum/utils/address.py +171 -0
  81. bitmart/ccxt/static_dependencies/ethereum/utils/applicators.py +151 -0
  82. bitmart/ccxt/static_dependencies/ethereum/utils/conversions.py +190 -0
  83. bitmart/ccxt/static_dependencies/ethereum/utils/currency.py +107 -0
  84. bitmart/ccxt/static_dependencies/ethereum/utils/curried/__init__.py +269 -0
  85. bitmart/ccxt/static_dependencies/ethereum/utils/debug.py +20 -0
  86. bitmart/ccxt/static_dependencies/ethereum/utils/decorators.py +132 -0
  87. bitmart/ccxt/static_dependencies/ethereum/utils/encoding.py +6 -0
  88. bitmart/ccxt/static_dependencies/ethereum/utils/exceptions.py +4 -0
  89. bitmart/ccxt/static_dependencies/ethereum/utils/functional.py +75 -0
  90. bitmart/ccxt/static_dependencies/ethereum/utils/hexadecimal.py +74 -0
  91. bitmart/ccxt/static_dependencies/ethereum/utils/humanize.py +188 -0
  92. bitmart/ccxt/static_dependencies/ethereum/utils/logging.py +159 -0
  93. bitmart/ccxt/static_dependencies/ethereum/utils/module_loading.py +31 -0
  94. bitmart/ccxt/static_dependencies/ethereum/utils/numeric.py +43 -0
  95. bitmart/ccxt/static_dependencies/ethereum/utils/py.typed +0 -0
  96. bitmart/ccxt/static_dependencies/ethereum/utils/toolz.py +76 -0
  97. bitmart/ccxt/static_dependencies/ethereum/utils/types.py +54 -0
  98. bitmart/ccxt/static_dependencies/ethereum/utils/typing/__init__.py +18 -0
  99. bitmart/ccxt/static_dependencies/ethereum/utils/typing/misc.py +14 -0
  100. bitmart/ccxt/static_dependencies/ethereum/utils/units.py +31 -0
  101. bitmart/ccxt/static_dependencies/keccak/__init__.py +3 -0
  102. bitmart/ccxt/static_dependencies/keccak/keccak.py +197 -0
  103. bitmart/ccxt/static_dependencies/lark/__init__.py +38 -0
  104. bitmart/ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
  105. bitmart/ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
  106. bitmart/ccxt/static_dependencies/lark/ast_utils.py +59 -0
  107. bitmart/ccxt/static_dependencies/lark/common.py +86 -0
  108. bitmart/ccxt/static_dependencies/lark/exceptions.py +292 -0
  109. bitmart/ccxt/static_dependencies/lark/grammar.py +130 -0
  110. bitmart/ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
  111. bitmart/ccxt/static_dependencies/lark/grammars/common.lark +59 -0
  112. bitmart/ccxt/static_dependencies/lark/grammars/lark.lark +62 -0
  113. bitmart/ccxt/static_dependencies/lark/grammars/python.lark +302 -0
  114. bitmart/ccxt/static_dependencies/lark/grammars/unicode.lark +7 -0
  115. bitmart/ccxt/static_dependencies/lark/indenter.py +143 -0
  116. bitmart/ccxt/static_dependencies/lark/lark.py +658 -0
  117. bitmart/ccxt/static_dependencies/lark/lexer.py +678 -0
  118. bitmart/ccxt/static_dependencies/lark/load_grammar.py +1428 -0
  119. bitmart/ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
  120. bitmart/ccxt/static_dependencies/lark/parser_frontends.py +257 -0
  121. bitmart/ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
  122. bitmart/ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
  123. bitmart/ccxt/static_dependencies/lark/parsers/earley.py +314 -0
  124. bitmart/ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
  125. bitmart/ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
  126. bitmart/ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
  127. bitmart/ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
  128. bitmart/ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
  129. bitmart/ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
  130. bitmart/ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
  131. bitmart/ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
  132. bitmart/ccxt/static_dependencies/lark/py.typed +0 -0
  133. bitmart/ccxt/static_dependencies/lark/reconstruct.py +107 -0
  134. bitmart/ccxt/static_dependencies/lark/tools/__init__.py +70 -0
  135. bitmart/ccxt/static_dependencies/lark/tools/nearley.py +202 -0
  136. bitmart/ccxt/static_dependencies/lark/tools/serialize.py +32 -0
  137. bitmart/ccxt/static_dependencies/lark/tools/standalone.py +196 -0
  138. bitmart/ccxt/static_dependencies/lark/tree.py +267 -0
  139. bitmart/ccxt/static_dependencies/lark/tree_matcher.py +186 -0
  140. bitmart/ccxt/static_dependencies/lark/tree_templates.py +180 -0
  141. bitmart/ccxt/static_dependencies/lark/utils.py +343 -0
  142. bitmart/ccxt/static_dependencies/lark/visitors.py +596 -0
  143. bitmart/ccxt/static_dependencies/marshmallow/__init__.py +81 -0
  144. bitmart/ccxt/static_dependencies/marshmallow/base.py +65 -0
  145. bitmart/ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
  146. bitmart/ccxt/static_dependencies/marshmallow/decorators.py +231 -0
  147. bitmart/ccxt/static_dependencies/marshmallow/error_store.py +60 -0
  148. bitmart/ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
  149. bitmart/ccxt/static_dependencies/marshmallow/fields.py +2114 -0
  150. bitmart/ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
  151. bitmart/ccxt/static_dependencies/marshmallow/py.typed +0 -0
  152. bitmart/ccxt/static_dependencies/marshmallow/schema.py +1228 -0
  153. bitmart/ccxt/static_dependencies/marshmallow/types.py +12 -0
  154. bitmart/ccxt/static_dependencies/marshmallow/utils.py +378 -0
  155. bitmart/ccxt/static_dependencies/marshmallow/validate.py +678 -0
  156. bitmart/ccxt/static_dependencies/marshmallow/warnings.py +2 -0
  157. bitmart/ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
  158. bitmart/ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
  159. bitmart/ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
  160. bitmart/ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
  161. bitmart/ccxt/static_dependencies/marshmallow_dataclass/py.typed +0 -0
  162. bitmart/ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
  163. bitmart/ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
  164. bitmart/ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
  165. bitmart/ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
  166. bitmart/ccxt/static_dependencies/marshmallow_oneofschema/py.typed +0 -0
  167. bitmart/ccxt/static_dependencies/msgpack/__init__.py +55 -0
  168. bitmart/ccxt/static_dependencies/msgpack/_cmsgpack.pyx +11 -0
  169. bitmart/ccxt/static_dependencies/msgpack/_packer.pyx +374 -0
  170. bitmart/ccxt/static_dependencies/msgpack/_unpacker.pyx +547 -0
  171. bitmart/ccxt/static_dependencies/msgpack/buff_converter.h +8 -0
  172. bitmart/ccxt/static_dependencies/msgpack/exceptions.py +48 -0
  173. bitmart/ccxt/static_dependencies/msgpack/ext.py +168 -0
  174. bitmart/ccxt/static_dependencies/msgpack/fallback.py +951 -0
  175. bitmart/ccxt/static_dependencies/msgpack/pack.h +89 -0
  176. bitmart/ccxt/static_dependencies/msgpack/pack_template.h +820 -0
  177. bitmart/ccxt/static_dependencies/msgpack/sysdep.h +194 -0
  178. bitmart/ccxt/static_dependencies/msgpack/unpack.h +391 -0
  179. bitmart/ccxt/static_dependencies/msgpack/unpack_define.h +95 -0
  180. bitmart/ccxt/static_dependencies/msgpack/unpack_template.h +464 -0
  181. bitmart/ccxt/static_dependencies/parsimonious/__init__.py +10 -0
  182. bitmart/ccxt/static_dependencies/parsimonious/exceptions.py +105 -0
  183. bitmart/ccxt/static_dependencies/parsimonious/expressions.py +479 -0
  184. bitmart/ccxt/static_dependencies/parsimonious/grammar.py +487 -0
  185. bitmart/ccxt/static_dependencies/parsimonious/nodes.py +325 -0
  186. bitmart/ccxt/static_dependencies/parsimonious/utils.py +40 -0
  187. bitmart/ccxt/static_dependencies/starknet/__init__.py +0 -0
  188. bitmart/ccxt/static_dependencies/starknet/abi/v0/__init__.py +2 -0
  189. bitmart/ccxt/static_dependencies/starknet/abi/v0/model.py +44 -0
  190. bitmart/ccxt/static_dependencies/starknet/abi/v0/parser.py +216 -0
  191. bitmart/ccxt/static_dependencies/starknet/abi/v0/schemas.py +72 -0
  192. bitmart/ccxt/static_dependencies/starknet/abi/v0/shape.py +63 -0
  193. bitmart/ccxt/static_dependencies/starknet/abi/v1/__init__.py +2 -0
  194. bitmart/ccxt/static_dependencies/starknet/abi/v1/core_structures.json +14 -0
  195. bitmart/ccxt/static_dependencies/starknet/abi/v1/model.py +39 -0
  196. bitmart/ccxt/static_dependencies/starknet/abi/v1/parser.py +220 -0
  197. bitmart/ccxt/static_dependencies/starknet/abi/v1/parser_transformer.py +179 -0
  198. bitmart/ccxt/static_dependencies/starknet/abi/v1/schemas.py +66 -0
  199. bitmart/ccxt/static_dependencies/starknet/abi/v1/shape.py +47 -0
  200. bitmart/ccxt/static_dependencies/starknet/abi/v2/__init__.py +2 -0
  201. bitmart/ccxt/static_dependencies/starknet/abi/v2/model.py +89 -0
  202. bitmart/ccxt/static_dependencies/starknet/abi/v2/parser.py +293 -0
  203. bitmart/ccxt/static_dependencies/starknet/abi/v2/parser_transformer.py +192 -0
  204. bitmart/ccxt/static_dependencies/starknet/abi/v2/schemas.py +132 -0
  205. bitmart/ccxt/static_dependencies/starknet/abi/v2/shape.py +107 -0
  206. bitmart/ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
  207. bitmart/ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
  208. bitmart/ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
  209. bitmart/ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
  210. bitmart/ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
  211. bitmart/ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
  212. bitmart/ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
  213. bitmart/ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
  214. bitmart/ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
  215. bitmart/ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
  216. bitmart/ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
  217. bitmart/ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
  218. bitmart/ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
  219. bitmart/ccxt/static_dependencies/starknet/common.py +15 -0
  220. bitmart/ccxt/static_dependencies/starknet/constants.py +39 -0
  221. bitmart/ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
  222. bitmart/ccxt/static_dependencies/starknet/hash/address.py +79 -0
  223. bitmart/ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
  224. bitmart/ccxt/static_dependencies/starknet/hash/selector.py +16 -0
  225. bitmart/ccxt/static_dependencies/starknet/hash/storage.py +12 -0
  226. bitmart/ccxt/static_dependencies/starknet/hash/utils.py +78 -0
  227. bitmart/ccxt/static_dependencies/starknet/models/__init__.py +0 -0
  228. bitmart/ccxt/static_dependencies/starknet/models/typed_data.py +45 -0
  229. bitmart/ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
  230. bitmart/ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
  231. bitmart/ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
  232. bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
  233. bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
  234. bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
  235. bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
  236. bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
  237. bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
  238. bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
  239. bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
  240. bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
  241. bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
  242. bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
  243. bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
  244. bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
  245. bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
  246. bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
  247. bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
  248. bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
  249. bitmart/ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
  250. bitmart/ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
  251. bitmart/ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
  252. bitmart/ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
  253. bitmart/ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
  254. bitmart/ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
  255. bitmart/ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
  256. bitmart/ccxt/static_dependencies/starknet/utils/schema.py +13 -0
  257. bitmart/ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
  258. bitmart/ccxt/static_dependencies/starkware/__init__.py +0 -0
  259. bitmart/ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
  260. bitmart/ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +50 -0
  261. bitmart/ccxt/static_dependencies/starkware/crypto/math_utils.py +78 -0
  262. bitmart/ccxt/static_dependencies/starkware/crypto/signature.py +2344 -0
  263. bitmart/ccxt/static_dependencies/starkware/crypto/utils.py +63 -0
  264. bitmart/ccxt/static_dependencies/sympy/__init__.py +0 -0
  265. bitmart/ccxt/static_dependencies/sympy/core/__init__.py +0 -0
  266. bitmart/ccxt/static_dependencies/sympy/core/intfunc.py +35 -0
  267. bitmart/ccxt/static_dependencies/sympy/external/__init__.py +0 -0
  268. bitmart/ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
  269. bitmart/ccxt/static_dependencies/sympy/external/importtools.py +187 -0
  270. bitmart/ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
  271. bitmart/ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
  272. bitmart/ccxt/static_dependencies/toolz/__init__.py +26 -0
  273. bitmart/ccxt/static_dependencies/toolz/_signatures.py +784 -0
  274. bitmart/ccxt/static_dependencies/toolz/_version.py +520 -0
  275. bitmart/ccxt/static_dependencies/toolz/compatibility.py +30 -0
  276. bitmart/ccxt/static_dependencies/toolz/curried/__init__.py +101 -0
  277. bitmart/ccxt/static_dependencies/toolz/curried/exceptions.py +22 -0
  278. bitmart/ccxt/static_dependencies/toolz/curried/operator.py +22 -0
  279. bitmart/ccxt/static_dependencies/toolz/dicttoolz.py +339 -0
  280. bitmart/ccxt/static_dependencies/toolz/functoolz.py +1049 -0
  281. bitmart/ccxt/static_dependencies/toolz/itertoolz.py +1057 -0
  282. bitmart/ccxt/static_dependencies/toolz/recipes.py +46 -0
  283. bitmart/ccxt/static_dependencies/toolz/utils.py +9 -0
  284. bitmart/ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
  285. bitmart/ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
  286. {bitmart-0.0.12.dist-info → bitmart-0.0.14.dist-info}/METADATA +1 -1
  287. bitmart-0.0.14.dist-info/RECORD +288 -0
  288. bitmart-0.0.12.dist-info/RECORD +0 -3
  289. {bitmart-0.0.12.dist-info → bitmart-0.0.14.dist-info}/WHEEL +0 -0
@@ -0,0 +1,1565 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
+ # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
+
6
+ import ccxt.async_support
7
+ from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheBySymbolBySide, ArrayCacheByTimestamp
8
+ from ccxt.async_support.base.ws.order_book_side import Asks, Bids
9
+ import hashlib
10
+ from ccxt.base.types import Any, Balances, Int, Market, Order, OrderBook, Position, Str, Strings, Ticker, Tickers, Trade
11
+ from ccxt.async_support.base.ws.client import Client
12
+ from typing import List
13
+ from ccxt.base.errors import ExchangeError
14
+ from ccxt.base.errors import AuthenticationError
15
+ from ccxt.base.errors import NotSupported
16
+
17
+
18
+ from ccxt.async_support import bitmart as bitmartAsync
19
+
20
+
21
+ class bitmart(bitmartAsync):
22
+
23
+ def describe(self) -> Any:
24
+ return self.deep_extend(super(bitmart, self).describe(), {
25
+ 'has': {
26
+ 'createOrderWs': False,
27
+ 'editOrderWs': False,
28
+ 'fetchOpenOrdersWs': False,
29
+ 'fetchOrderWs': False,
30
+ 'cancelOrderWs': False,
31
+ 'cancelOrdersWs': False,
32
+ 'cancelAllOrdersWs': False,
33
+ 'ws': True,
34
+ 'watchBalance': True,
35
+ 'watchTicker': True,
36
+ 'watchTickers': True,
37
+ 'watchBidsAsks': True,
38
+ 'watchOrderBook': True,
39
+ 'watchOrderBookForSymbols': True,
40
+ 'watchOrders': True,
41
+ 'watchTrades': True,
42
+ 'watchTradesForSymbols': True,
43
+ 'watchOHLCV': True,
44
+ 'watchPosition': 'emulated',
45
+ 'watchPositions': True,
46
+ },
47
+ 'urls': {
48
+ 'api': {
49
+ 'ws': {
50
+ 'spot': {
51
+ 'public': 'wss://ws-manager-compress.{hostname}/api?protocol=1.1',
52
+ 'private': 'wss://ws-manager-compress.{hostname}/user?protocol=1.1',
53
+ },
54
+ 'swap': {
55
+ 'public': 'wss://openapi-ws-v2.{hostname}/api?protocol=1.1',
56
+ 'private': 'wss://openapi-ws-v2.{hostname}/user?protocol=1.1',
57
+ },
58
+ },
59
+ },
60
+ },
61
+ 'options': {
62
+ 'defaultType': 'spot',
63
+ 'watchBalance': {
64
+ 'fetchBalanceSnapshot': True, # or False
65
+ 'awaitBalanceSnapshot': False, # whether to wait for the balance snapshot before providing updates
66
+ },
67
+ #
68
+ # orderbook channels can have:
69
+ # - 'depth5', 'depth20', 'depth50' # these endpoints emit full Orderbooks once in every 500ms
70
+ # - 'depth/increase100' # self endpoint is preferred, because it emits once in 100ms. however, when self value is chosen, it only affects spot-market, but contracts markets automatically `depth50` will be being used
71
+ 'watchOrderBook': {
72
+ 'depth': 'depth/increase100',
73
+ },
74
+ 'watchOrderBookForSymbols': {
75
+ 'depth': 'depth/increase100',
76
+ },
77
+ 'ws': {
78
+ 'inflate': True,
79
+ },
80
+ 'timeframes': {
81
+ '1m': '1m',
82
+ '3m': '3m',
83
+ '5m': '5m',
84
+ '15m': '15m',
85
+ '30m': '30m',
86
+ '45m': '45m',
87
+ '1h': '1H',
88
+ '2h': '2H',
89
+ '3h': '3H',
90
+ '4h': '4H',
91
+ '1d': '1D',
92
+ '1w': '1W',
93
+ '1M': '1M',
94
+ },
95
+ },
96
+ 'streaming': {
97
+ 'keepAlive': 15000,
98
+ },
99
+ })
100
+
101
+ async def subscribe(self, channel, symbol, type, params={}):
102
+ market = self.market(symbol)
103
+ url = self.implode_hostname(self.urls['api']['ws'][type]['public'])
104
+ request = {}
105
+ messageHash = None
106
+ if type == 'spot':
107
+ messageHash = 'spot/' + channel + ':' + market['id']
108
+ request = {
109
+ 'op': 'subscribe',
110
+ 'args': [messageHash],
111
+ }
112
+ else:
113
+ messageHash = 'futures/' + channel + ':' + market['id']
114
+ speed = self.safe_string(params, 'speed')
115
+ if speed is not None:
116
+ params = self.omit(params, 'speed')
117
+ messageHash += ':' + speed
118
+ request = {
119
+ 'action': 'subscribe',
120
+ 'args': [messageHash],
121
+ }
122
+ return await self.watch(url, messageHash, self.deep_extend(request, params), messageHash)
123
+
124
+ async def subscribe_multiple(self, channel: str, type: str, symbols: Strings = None, params={}):
125
+ symbols = self.market_symbols(symbols, type, False, True)
126
+ url = self.implode_hostname(self.urls['api']['ws'][type]['public'])
127
+ channelType = 'spot' if (type == 'spot') else 'futures'
128
+ actionType = 'op' if (type == 'spot') else 'action'
129
+ rawSubscriptions = []
130
+ messageHashes = []
131
+ for i in range(0, len(symbols)):
132
+ market = self.market(symbols[i])
133
+ message = channelType + '/' + channel + ':' + market['id']
134
+ rawSubscriptions.append(message)
135
+ messageHashes.append(channel + ':' + market['symbol'])
136
+ # exclusion, futures "tickers" need one generic request for all symbols
137
+ # if (type != 'spot') and (channel == 'ticker'):
138
+ # rawSubscriptions = [channelType + '/' + channel]
139
+ # }
140
+ # Exchange update from 2025-02-11 supports subscription by trading pair for swap
141
+ request: dict = {
142
+ 'args': rawSubscriptions,
143
+ }
144
+ request[actionType] = 'subscribe'
145
+ return await self.watch_multiple(url, messageHashes, self.deep_extend(request, params), rawSubscriptions)
146
+
147
+ async def watch_balance(self, params={}) -> Balances:
148
+ """
149
+
150
+ https://developer-pro.bitmart.com/en/spot/#private-balance-change
151
+ https://developer-pro.bitmart.com/en/futuresv2/#private-assets-channel
152
+
153
+ watch balance and get the amount of funds available for trading or funds locked in orders
154
+ :param dict [params]: extra parameters specific to the exchange API endpoint
155
+ :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
156
+ """
157
+ await self.load_markets()
158
+ type = 'spot'
159
+ type, params = self.handle_market_type_and_params('watchBalance', None, params)
160
+ await self.authenticate(type, params)
161
+ request = {}
162
+ if type == 'spot':
163
+ request = {
164
+ 'op': 'subscribe',
165
+ 'args': ['spot/user/balance:BALANCE_UPDATE'],
166
+ }
167
+ else:
168
+ request = {
169
+ 'action': 'subscribe',
170
+ 'args': ['futures/asset:USDT', 'futures/asset:BTC', 'futures/asset:ETH'],
171
+ }
172
+ messageHash = 'balance:' + type
173
+ url = self.implode_hostname(self.urls['api']['ws'][type]['private'])
174
+ client = self.client(url)
175
+ self.set_balance_cache(client, type, messageHash)
176
+ fetchBalanceSnapshot = None
177
+ awaitBalanceSnapshot = None
178
+ fetchBalanceSnapshot, params = self.handle_option_and_params(self.options, 'watchBalance', 'fetchBalanceSnapshot', True)
179
+ awaitBalanceSnapshot, params = self.handle_option_and_params(self.options, 'watchBalance', 'awaitBalanceSnapshot', False)
180
+ if fetchBalanceSnapshot and awaitBalanceSnapshot:
181
+ await client.future(type + ':fetchBalanceSnapshot')
182
+ return await self.watch(url, messageHash, self.deep_extend(request, params), messageHash)
183
+
184
+ def set_balance_cache(self, client: Client, type, subscribeHash):
185
+ if subscribeHash in client.subscriptions:
186
+ return
187
+ options = self.safe_value(self.options, 'watchBalance')
188
+ snapshot = self.safe_bool(options, 'fetchBalanceSnapshot', True)
189
+ if snapshot:
190
+ messageHash = type + ':' + 'fetchBalanceSnapshot'
191
+ if not (messageHash in client.futures):
192
+ client.future(messageHash)
193
+ self.spawn(self.load_balance_snapshot, client, messageHash, type)
194
+ self.balance[type] = {}
195
+ # without self comment, transpilation breaks for some reason...
196
+
197
+ async def load_balance_snapshot(self, client, messageHash, type):
198
+ response = await self.fetch_balance({'type': type})
199
+ self.balance[type] = self.extend(response, self.safe_value(self.balance, type, {}))
200
+ # don't remove the future from the .futures cache
201
+ future = client.futures[messageHash]
202
+ future.resolve()
203
+ client.resolve(self.balance[type], 'balance:' + type)
204
+
205
+ def handle_balance(self, client: Client, message):
206
+ #
207
+ # spot
208
+ # {
209
+ # "data":[
210
+ # {
211
+ # "balance_details":[
212
+ # {
213
+ # "av_bal":"0.206000000000000000000000000000",
214
+ # "ccy":"LTC",
215
+ # "fz_bal":"0.100000000000000000000000000000"
216
+ # }
217
+ # ],
218
+ # "event_time":"1701632345415",
219
+ # "event_type":"TRANSACTION_COMPLETED"
220
+ # }
221
+ # ],
222
+ # "table":"spot/user/balance"
223
+ # }
224
+ # swap
225
+ # {
226
+ # group: 'futures/asset:USDT',
227
+ # data: {
228
+ # currency: 'USDT',
229
+ # available_balance: '37.19688649135',
230
+ # position_deposit: '0.788687546',
231
+ # frozen_balance: '0'
232
+ # }
233
+ # }
234
+ #
235
+ channel = self.safe_string_2(message, 'table', 'group')
236
+ data = self.safe_value(message, 'data')
237
+ if data is None:
238
+ return
239
+ isSpot = (channel.find('spot') >= 0)
240
+ type = 'spot' if isSpot else 'swap'
241
+ self.balance[type]['info'] = message
242
+ if isSpot:
243
+ if not isinstance(data, list):
244
+ return
245
+ for i in range(0, len(data)):
246
+ timestamp = self.safe_integer(message, 'event_time')
247
+ self.balance[type]['timestamp'] = timestamp
248
+ self.balance[type]['datetime'] = self.iso8601(timestamp)
249
+ balanceDetails = self.safe_value(data[i], 'balance_details', [])
250
+ for ii in range(0, len(balanceDetails)):
251
+ rawBalance = balanceDetails[i]
252
+ account = self.account()
253
+ currencyId = self.safe_string(rawBalance, 'ccy')
254
+ code = self.safe_currency_code(currencyId)
255
+ account['free'] = self.safe_string(rawBalance, 'av_bal')
256
+ account['used'] = self.safe_string(rawBalance, 'fz_bal')
257
+ self.balance[type][code] = account
258
+ else:
259
+ currencyId = self.safe_string(data, 'currency')
260
+ code = self.safe_currency_code(currencyId)
261
+ account = self.account()
262
+ account['free'] = self.safe_string(data, 'available_balance')
263
+ account['used'] = self.safe_string(data, 'frozen_balance')
264
+ self.balance[type][code] = account
265
+ self.balance[type] = self.safe_balance(self.balance[type])
266
+ messageHash = 'balance:' + type
267
+ client.resolve(self.balance[type], messageHash)
268
+
269
+ async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
270
+ """
271
+
272
+ https://developer-pro.bitmart.com/en/spot/#public-trade-channel
273
+ https://developer-pro.bitmart.com/en/futuresv2/#public-trade-channel
274
+
275
+ get the list of most recent trades for a particular symbol
276
+ :param str symbol: unified symbol of the market to fetch trades for
277
+ :param int [since]: timestamp in ms of the earliest trade to fetch
278
+ :param int [limit]: the maximum amount of trades to fetch
279
+ :param dict [params]: extra parameters specific to the exchange API endpoint
280
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
281
+ """
282
+ return await self.watch_trades_for_symbols([symbol], since, limit, params)
283
+
284
+ async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
285
+ """
286
+
287
+ https://developer-pro.bitmart.com/en/spot/#public-trade-channel
288
+
289
+ get the list of most recent trades for a list of symbols
290
+ :param str[] symbols: unified symbol of the market to fetch trades for
291
+ :param int [since]: timestamp in ms of the earliest trade to fetch
292
+ :param int [limit]: the maximum amount of trades to fetch
293
+ :param dict [params]: extra parameters specific to the exchange API endpoint
294
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
295
+ """
296
+ await self.load_markets()
297
+ marketType = None
298
+ symbols, marketType, params = self.get_params_for_multiple_sub('watchTradesForSymbols', symbols, limit, params)
299
+ channelName = 'trade'
300
+ trades = await self.subscribe_multiple(channelName, marketType, symbols, params)
301
+ if self.newUpdates:
302
+ first = self.safe_dict(trades, 0)
303
+ tradeSymbol = self.safe_string(first, 'symbol')
304
+ limit = trades.getLimit(tradeSymbol, limit)
305
+ return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
306
+
307
+ def get_params_for_multiple_sub(self, methodName: str, symbols: List[str], limit: Int = None, params={}):
308
+ symbols = self.market_symbols(symbols, None, False, True)
309
+ length = len(symbols)
310
+ if length > 20:
311
+ raise NotSupported(self.id + ' ' + methodName + '() accepts a maximum of 20 symbols in one request')
312
+ market = self.market(symbols[0])
313
+ marketType = None
314
+ marketType, params = self.handle_market_type_and_params(methodName, market, params)
315
+ return [symbols, marketType, params]
316
+
317
+ async def watch_ticker(self, symbol: str, params={}) -> Ticker:
318
+ """
319
+
320
+ https://developer-pro.bitmart.com/en/spot/#public-ticker-channel
321
+ https://developer-pro.bitmart.com/en/futuresv2/#public-ticker-channel
322
+
323
+ watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
324
+ :param str symbol: unified symbol of the market to fetch the ticker for
325
+ :param dict [params]: extra parameters specific to the exchange API endpoint
326
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
327
+ """
328
+ await self.load_markets()
329
+ symbol = self.symbol(symbol)
330
+ tickers = await self.watch_tickers([symbol], params)
331
+ return tickers[symbol]
332
+
333
+ async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
334
+ """
335
+
336
+ https://developer-pro.bitmart.com/en/spot/#public-ticker-channel
337
+ https://developer-pro.bitmart.com/en/futuresv2/#public-ticker-channel
338
+
339
+ watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
340
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
341
+ :param dict [params]: extra parameters specific to the exchange API endpoint
342
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
343
+ """
344
+ await self.load_markets()
345
+ market = self.get_market_from_symbols(symbols)
346
+ marketType = None
347
+ marketType, params = self.handle_market_type_and_params('watchTickers', market, params)
348
+ ticker = await self.subscribe_multiple('ticker', marketType, symbols, params)
349
+ if self.newUpdates:
350
+ tickers: dict = {}
351
+ tickers[ticker['symbol']] = ticker
352
+ return tickers
353
+ return self.filter_by_array(self.tickers, 'symbol', symbols)
354
+
355
+ async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
356
+ """
357
+
358
+ https://developer-pro.bitmart.com/en/spot/#public-ticker-channel
359
+ https://developer-pro.bitmart.com/en/futuresv2/#public-ticker-channel
360
+
361
+ watches best bid & ask for symbols
362
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
363
+ :param dict [params]: extra parameters specific to the exchange API endpoint
364
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
365
+ """
366
+ await self.load_markets()
367
+ symbols = self.market_symbols(symbols, None, False)
368
+ firstMarket = self.get_market_from_symbols(symbols)
369
+ marketType = None
370
+ marketType, params = self.handle_market_type_and_params('watchBidsAsks', firstMarket, params)
371
+ url = self.implode_hostname(self.urls['api']['ws'][marketType]['public'])
372
+ channelType = 'spot' if (marketType == 'spot') else 'futures'
373
+ actionType = 'op' if (marketType == 'spot') else 'action'
374
+ rawSubscriptions = []
375
+ messageHashes = []
376
+ for i in range(0, len(symbols)):
377
+ market = self.market(symbols[i])
378
+ rawSubscriptions.append(channelType + '/ticker:' + market['id'])
379
+ messageHashes.append('bidask:' + symbols[i])
380
+ if marketType != 'spot':
381
+ rawSubscriptions = [channelType + '/ticker']
382
+ request: dict = {
383
+ 'args': rawSubscriptions,
384
+ }
385
+ request[actionType] = 'subscribe'
386
+ newTickers = await self.watch_multiple(url, messageHashes, request, rawSubscriptions)
387
+ if self.newUpdates:
388
+ tickers: dict = {}
389
+ tickers[newTickers['symbol']] = newTickers
390
+ return tickers
391
+ return self.filter_by_array(self.bidsasks, 'symbol', symbols)
392
+
393
+ def handle_bid_ask(self, client: Client, message):
394
+ table = self.safe_string(message, 'table')
395
+ isSpot = (table is not None)
396
+ rawTickers = []
397
+ if isSpot:
398
+ rawTickers = self.safe_list(message, 'data', [])
399
+ else:
400
+ rawTickers = [self.safe_value(message, 'data', {})]
401
+ if not len(rawTickers):
402
+ return
403
+ for i in range(0, len(rawTickers)):
404
+ ticker = self.parse_ws_bid_ask(rawTickers[i])
405
+ symbol = ticker['symbol']
406
+ self.bidsasks[symbol] = ticker
407
+ messageHash = 'bidask:' + symbol
408
+ client.resolve(ticker, messageHash)
409
+
410
+ def parse_ws_bid_ask(self, ticker, market=None):
411
+ marketId = self.safe_string(ticker, 'symbol')
412
+ market = self.safe_market(marketId, market)
413
+ symbol = self.safe_string(market, 'symbol')
414
+ timestamp = self.safe_integer(ticker, 'ms_t')
415
+ return self.safe_ticker({
416
+ 'symbol': symbol,
417
+ 'timestamp': timestamp,
418
+ 'datetime': self.iso8601(timestamp),
419
+ 'ask': self.safe_string_2(ticker, 'ask_px', 'ask_price'),
420
+ 'askVolume': self.safe_string_2(ticker, 'ask_sz', 'ask_vol'),
421
+ 'bid': self.safe_string_2(ticker, 'bid_px', 'bid_price'),
422
+ 'bidVolume': self.safe_string_2(ticker, 'bid_sz', 'bid_vol'),
423
+ 'info': ticker,
424
+ }, market)
425
+
426
+ async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
427
+ """
428
+ watches information on multiple orders made by the user
429
+
430
+ https://developer-pro.bitmart.com/en/spot/#private-order-progress
431
+ https://developer-pro.bitmart.com/en/futuresv2/#private-order-channel
432
+
433
+ :param str symbol: unified market symbol of the market orders were made in
434
+ :param int [since]: the earliest time in ms to fetch orders for
435
+ :param int [limit]: the maximum number of order structures to retrieve
436
+ :param dict [params]: extra parameters specific to the exchange API endpoint
437
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
438
+ """
439
+ await self.load_markets()
440
+ market = None
441
+ messageHash = 'orders'
442
+ if symbol is not None:
443
+ symbol = self.symbol(symbol)
444
+ market = self.market(symbol)
445
+ messageHash = 'orders::' + symbol
446
+ type = 'spot'
447
+ type, params = self.handle_market_type_and_params('watchOrders', market, params)
448
+ await self.authenticate(type, params)
449
+ request = None
450
+ if type == 'spot':
451
+ argsRequest = 'spot/user/order:'
452
+ if symbol is not None:
453
+ argsRequest += market['id']
454
+ else:
455
+ argsRequest = 'spot/user/orders:ALL_SYMBOLS'
456
+ request = {
457
+ 'op': 'subscribe',
458
+ 'args': [argsRequest],
459
+ }
460
+ else:
461
+ request = {
462
+ 'action': 'subscribe',
463
+ 'args': ['futures/order'],
464
+ }
465
+ url = self.implode_hostname(self.urls['api']['ws'][type]['private'])
466
+ newOrders = await self.watch(url, messageHash, self.deep_extend(request, params), messageHash)
467
+ if self.newUpdates:
468
+ return newOrders
469
+ return self.filter_by_symbol_since_limit(self.orders, symbol, since, limit, True)
470
+
471
+ def handle_orders(self, client: Client, message):
472
+ #
473
+ # spot
474
+ # {
475
+ # "data":[
476
+ # {
477
+ # "symbol": "LTC_USDT",
478
+ # "notional": '',
479
+ # "side": "buy",
480
+ # "last_fill_time": "0",
481
+ # "ms_t": "1646216634000",
482
+ # "type": "limit",
483
+ # "filled_notional": "0.000000000000000000000000000000",
484
+ # "last_fill_price": "0",
485
+ # "size": "0.500000000000000000000000000000",
486
+ # "price": "50.000000000000000000000000000000",
487
+ # "last_fill_count": "0",
488
+ # "filled_size": "0.000000000000000000000000000000",
489
+ # "margin_trading": "0",
490
+ # "state": "8",
491
+ # "order_id": "24807076628",
492
+ # "order_type": "0"
493
+ # }
494
+ # ],
495
+ # "table":"spot/user/order"
496
+ # }
497
+ # swap
498
+ # {
499
+ # "group":"futures/order",
500
+ # "data":[
501
+ # {
502
+ # "action":2,
503
+ # "order":{
504
+ # "order_id":"2312045036986775",
505
+ # "client_order_id":"",
506
+ # "price":"71.61707928",
507
+ # "size":"1",
508
+ # "symbol":"LTCUSDT",
509
+ # "state":1,
510
+ # "side":4,
511
+ # "type":"market",
512
+ # "leverage":"1",
513
+ # "open_type":"cross",
514
+ # "deal_avg_price":"0",
515
+ # "deal_size":"0",
516
+ # "create_time":1701625324646,
517
+ # "update_time":1701625324640,
518
+ # "plan_order_id":"",
519
+ # "last_trade":null
520
+ # }
521
+ # }
522
+ # ]
523
+ # }
524
+ #
525
+ orders = self.safe_value(message, 'data')
526
+ if orders is None:
527
+ return
528
+ ordersLength = len(orders)
529
+ newOrders = []
530
+ symbols: dict = {}
531
+ if ordersLength > 0:
532
+ limit = self.safe_integer(self.options, 'ordersLimit', 1000)
533
+ if self.orders is None:
534
+ self.orders = ArrayCacheBySymbolById(limit)
535
+ stored = self.orders
536
+ for i in range(0, len(orders)):
537
+ order = self.parse_ws_order(orders[i])
538
+ stored.append(order)
539
+ newOrders.append(order)
540
+ symbol = order['symbol']
541
+ symbols[symbol] = True
542
+ messageHash = 'orders'
543
+ symbolKeys = list(symbols.keys())
544
+ for i in range(0, len(symbolKeys)):
545
+ symbol = symbolKeys[i]
546
+ symbolSpecificMessageHash = messageHash + '::' + symbol
547
+ client.resolve(newOrders, symbolSpecificMessageHash)
548
+ client.resolve(newOrders, messageHash)
549
+
550
+ def parse_ws_order(self, order: dict, market: Market = None):
551
+ #
552
+ # spot
553
+ # {
554
+ # "symbol": "LTC_USDT",
555
+ # "notional": '',
556
+ # "side": "buy",
557
+ # "last_fill_time": "0",
558
+ # "ms_t": "1646216634000",
559
+ # "type": "limit",
560
+ # "filled_notional": "0.000000000000000000000000000000",
561
+ # "last_fill_price": "0",
562
+ # "size": "0.500000000000000000000000000000",
563
+ # "price": "50.000000000000000000000000000000",
564
+ # "last_fill_count": "0",
565
+ # "filled_size": "0.000000000000000000000000000000",
566
+ # "margin_trading": "0",
567
+ # "state": "8",
568
+ # "order_id": "24807076628",
569
+ # "order_type": "0"
570
+ # }
571
+ # swap
572
+ # {
573
+ # "action":2,
574
+ # "order":{
575
+ # "order_id":"2312045036986775",
576
+ # "client_order_id":"",
577
+ # "price":"71.61707928",
578
+ # "size":"1",
579
+ # "symbol":"LTCUSDT",
580
+ # "state":1,
581
+ # "side":4,
582
+ # "type":"market",
583
+ # "leverage":"1",
584
+ # "open_type":"cross",
585
+ # "deal_avg_price":"0",
586
+ # "deal_size":"0",
587
+ # "create_time":1701625324646,
588
+ # "update_time":1701625324640,
589
+ # "plan_order_id":"",
590
+ # "last_trade":null
591
+ # }
592
+ # }
593
+ #
594
+ action = self.safe_number(order, 'action')
595
+ isSpot = (action is None)
596
+ if isSpot:
597
+ marketId = self.safe_string(order, 'symbol')
598
+ market = self.safe_market(marketId, market, '_', 'spot')
599
+ id = self.safe_string(order, 'order_id')
600
+ clientOrderId = self.safe_string(order, 'clientOid')
601
+ price = self.safe_string(order, 'price')
602
+ filled = self.safe_string(order, 'filled_size')
603
+ amount = self.safe_string(order, 'size')
604
+ type = self.safe_string(order, 'type')
605
+ rawState = self.safe_string(order, 'state')
606
+ status = self.parse_order_status_by_type(market['type'], rawState)
607
+ timestamp = self.safe_integer(order, 'ms_t')
608
+ symbol = market['symbol']
609
+ side = self.safe_string_lower(order, 'side')
610
+ return self.safe_order({
611
+ 'info': order,
612
+ 'symbol': symbol,
613
+ 'id': id,
614
+ 'clientOrderId': clientOrderId,
615
+ 'timestamp': None,
616
+ 'datetime': None,
617
+ 'lastTradeTimestamp': timestamp,
618
+ 'type': type,
619
+ 'timeInForce': None,
620
+ 'postOnly': None,
621
+ 'side': side,
622
+ 'price': price,
623
+ 'stopPrice': None,
624
+ 'triggerPrice': None,
625
+ 'amount': amount,
626
+ 'cost': None,
627
+ 'average': None,
628
+ 'filled': filled,
629
+ 'remaining': None,
630
+ 'status': status,
631
+ 'fee': None,
632
+ 'trades': None,
633
+ }, market)
634
+ else:
635
+ orderInfo = self.safe_value(order, 'order')
636
+ marketId = self.safe_string(orderInfo, 'symbol')
637
+ symbol = self.safe_symbol(marketId, market, '', 'swap')
638
+ orderId = self.safe_string(orderInfo, 'order_id')
639
+ timestamp = self.safe_integer(orderInfo, 'create_time')
640
+ updatedTimestamp = self.safe_integer(orderInfo, 'update_time')
641
+ lastTrade = self.safe_value(orderInfo, 'last_trade')
642
+ cachedOrders = self.orders
643
+ orders = self.safe_value(cachedOrders.hashmap, symbol, {})
644
+ cachedOrder = self.safe_value(orders, orderId)
645
+ trades = None
646
+ if cachedOrder is not None:
647
+ trades = self.safe_value(order, 'trades')
648
+ if lastTrade is not None:
649
+ if trades is None:
650
+ trades = []
651
+ trades.append(lastTrade)
652
+ return self.safe_order({
653
+ 'info': order,
654
+ 'symbol': symbol,
655
+ 'id': orderId,
656
+ 'clientOrderId': self.safe_string(orderInfo, 'client_order_id'),
657
+ 'timestamp': timestamp,
658
+ 'datetime': self.iso8601(timestamp),
659
+ 'lastTradeTimestamp': updatedTimestamp,
660
+ 'type': self.safe_string(orderInfo, 'type'),
661
+ 'timeInForce': None,
662
+ 'postOnly': None,
663
+ 'side': self.parse_ws_order_side(self.safe_string(orderInfo, 'side')),
664
+ 'price': self.safe_string(orderInfo, 'price'),
665
+ 'stopPrice': None,
666
+ 'triggerPrice': None,
667
+ 'amount': self.safe_string(orderInfo, 'size'),
668
+ 'cost': None,
669
+ 'average': self.safe_string(orderInfo, 'deal_avg_price'),
670
+ 'filled': self.safe_string(orderInfo, 'deal_size'),
671
+ 'remaining': None,
672
+ 'status': self.parse_ws_order_status(self.safe_string(order, 'action')),
673
+ 'fee': None,
674
+ 'trades': trades,
675
+ }, market)
676
+
677
+ def parse_ws_order_status(self, statusId):
678
+ statuses: dict = {
679
+ '1': 'closed', # match deal
680
+ '2': 'open', # submit order
681
+ '3': 'canceled', # cancel order
682
+ '4': 'closed', # liquidate cancel order
683
+ '5': 'canceled', # adl cancel order
684
+ '6': 'open', # part liquidate
685
+ '7': 'open', # bankrupty order
686
+ '8': 'closed', # passive adl match deal
687
+ '9': 'closed', # active adl match deal
688
+ }
689
+ return self.safe_string(statuses, statusId, statusId)
690
+
691
+ def parse_ws_order_side(self, sideId):
692
+ sides: dict = {
693
+ '1': 'buy', # buy_open_long
694
+ '2': 'buy', # buy_close_short
695
+ '3': 'sell', # sell_close_long
696
+ '4': 'sell', # sell_open_short
697
+ }
698
+ return self.safe_string(sides, sideId, sideId)
699
+
700
+ async def watch_positions(self, symbols: Strings = None, since: Int = None, limit: Int = None, params={}) -> List[Position]:
701
+ """
702
+
703
+ https://developer-pro.bitmart.com/en/futures/#private-position-channel
704
+
705
+ watch all open positions
706
+ :param str[]|None symbols: list of unified market symbols
707
+ :param int [since]: the earliest time in ms to fetch positions
708
+ :param int [limit]: the maximum number of positions to retrieve
709
+ :param dict params: extra parameters specific to the exchange API endpoint
710
+ :returns dict[]: a list of `position structure <https://docs.ccxt.com/en/latest/manual.html#position-structure>`
711
+ """
712
+ await self.load_markets()
713
+ type = 'swap'
714
+ await self.authenticate(type, params)
715
+ symbols = self.market_symbols(symbols, 'swap', True, True, False)
716
+ messageHash = 'positions'
717
+ if symbols is not None:
718
+ messageHash += '::' + ','.join(symbols)
719
+ subscriptionHash = 'futures/position'
720
+ request: dict = {
721
+ 'action': 'subscribe',
722
+ 'args': ['futures/position'],
723
+ }
724
+ url = self.implode_hostname(self.urls['api']['ws'][type]['private'])
725
+ newPositions = await self.watch(url, messageHash, self.deep_extend(request, params), subscriptionHash)
726
+ if self.newUpdates:
727
+ return newPositions
728
+ return self.filter_by_symbols_since_limit(self.positions, symbols, since, limit)
729
+
730
+ def handle_positions(self, client: Client, message):
731
+ #
732
+ # {
733
+ # "group":"futures/position",
734
+ # "data":[
735
+ # {
736
+ # "symbol":"LTCUSDT",
737
+ # "hold_volume":"5",
738
+ # "position_type":2,
739
+ # "open_type":2,
740
+ # "frozen_volume":"0",
741
+ # "close_volume":"0",
742
+ # "hold_avg_price":"71.582",
743
+ # "close_avg_price":"0",
744
+ # "open_avg_price":"71.582",
745
+ # "liquidate_price":"0",
746
+ # "create_time":1701623327513,
747
+ # "update_time":1701627620439
748
+ # },
749
+ # {
750
+ # "symbol":"LTCUSDT",
751
+ # "hold_volume":"6",
752
+ # "position_type":1,
753
+ # "open_type":2,
754
+ # "frozen_volume":"0",
755
+ # "close_volume":"0",
756
+ # "hold_avg_price":"71.681666666666666667",
757
+ # "close_avg_price":"0",
758
+ # "open_avg_price":"71.681666666666666667",
759
+ # "liquidate_price":"0",
760
+ # "create_time":1701621167225,
761
+ # "update_time":1701628152614
762
+ # }
763
+ # ]
764
+ # }
765
+ #
766
+ data = self.safe_value(message, 'data', [])
767
+ if self.positions is None:
768
+ self.positions = ArrayCacheBySymbolBySide()
769
+ cache = self.positions
770
+ newPositions = []
771
+ for i in range(0, len(data)):
772
+ rawPosition = data[i]
773
+ position = self.parse_ws_position(rawPosition)
774
+ newPositions.append(position)
775
+ cache.append(position)
776
+ messageHashes = self.find_message_hashes(client, 'positions::')
777
+ for i in range(0, len(messageHashes)):
778
+ messageHash = messageHashes[i]
779
+ parts = messageHash.split('::')
780
+ symbolsString = parts[1]
781
+ symbols = symbolsString.split(',')
782
+ positions = self.filter_by_array(newPositions, 'symbol', symbols, False)
783
+ if not self.is_empty(positions):
784
+ client.resolve(positions, messageHash)
785
+ client.resolve(newPositions, 'positions')
786
+
787
+ def parse_ws_position(self, position, market: Market = None):
788
+ #
789
+ # {
790
+ # "symbol":"LTCUSDT",
791
+ # "hold_volume":"6",
792
+ # "position_type":1,
793
+ # "open_type":2,
794
+ # "frozen_volume":"0",
795
+ # "close_volume":"0",
796
+ # "hold_avg_price":"71.681666666666666667",
797
+ # "close_avg_price":"0",
798
+ # "open_avg_price":"71.681666666666666667",
799
+ # "liquidate_price":"0",
800
+ # "create_time":1701621167225,
801
+ # "update_time":1701628152614
802
+ # }
803
+ #
804
+ marketId = self.safe_string(position, 'symbol')
805
+ market = self.safe_market(marketId, market, None, 'swap')
806
+ symbol = market['symbol']
807
+ openTimestamp = self.safe_integer(position, 'create_time')
808
+ timestamp = self.safe_integer(position, 'update_time')
809
+ side = self.safe_integer(position, 'position_type')
810
+ marginModeId = self.safe_integer(position, 'open_type')
811
+ return self.safe_position({
812
+ 'info': position,
813
+ 'id': None,
814
+ 'symbol': symbol,
815
+ 'timestamp': openTimestamp,
816
+ 'datetime': self.iso8601(openTimestamp),
817
+ 'lastUpdateTimestamp': timestamp,
818
+ 'hedged': None,
819
+ 'side': 'long' if (side == 1) else 'short',
820
+ 'contracts': self.safe_number(position, 'hold_volume'),
821
+ 'contractSize': self.safe_number(market, 'contractSize'),
822
+ 'entryPrice': self.safe_number(position, 'open_avg_price'),
823
+ 'markPrice': self.safe_number(position, 'hold_avg_price'),
824
+ 'lastPrice': None,
825
+ 'notional': None,
826
+ 'leverage': None,
827
+ 'collateral': None,
828
+ 'initialMargin': None,
829
+ 'initialMarginPercentage': None,
830
+ 'maintenanceMargin': None,
831
+ 'maintenanceMarginPercentage': None,
832
+ 'unrealizedPnl': None,
833
+ 'realizedPnl': None,
834
+ 'liquidationPrice': self.safe_number(position, 'liquidate_price'),
835
+ 'marginMode': 'isolated' if (marginModeId == 1) else 'cross',
836
+ 'percentage': None,
837
+ 'marginRatio': None,
838
+ 'stopLossPrice': None,
839
+ 'takeProfitPrice': None,
840
+ })
841
+
842
+ def handle_trade(self, client: Client, message):
843
+ #
844
+ # spot
845
+ # {
846
+ # "table": "spot/trade",
847
+ # "data": [
848
+ # {
849
+ # "price": "52700.50",
850
+ # "s_t": 1630982050,
851
+ # "side": "buy",
852
+ # "size": "0.00112",
853
+ # "symbol": "BTC_USDT"
854
+ # },
855
+ # ]
856
+ # }
857
+ #
858
+ # swap
859
+ # {
860
+ # "group":"futures/trade:BTCUSDT",
861
+ # "data":[
862
+ # {
863
+ # "trade_id":6798697637,
864
+ # "contract_id":1,
865
+ # "symbol":"BTCUSDT",
866
+ # "deal_price":"39735.8",
867
+ # "deal_vol":"2",
868
+ # "type":0,
869
+ # "way":1,
870
+ # "create_time":1701618503,
871
+ # "create_time_mill":1701618503517,
872
+ # "created_at":"2023-12-03T15:48:23.517518538Z"
873
+ # }
874
+ # ]
875
+ # }
876
+ #
877
+ data = self.safe_value(message, 'data')
878
+ if data is None:
879
+ return
880
+ symbol = None
881
+ length = len(data)
882
+ isSwap = ('group' in message)
883
+ if isSwap:
884
+ # in swap, chronologically decreasing: 1709536849322, 1709536848954,
885
+ for i in range(0, length):
886
+ index = length - i - 1
887
+ symbol = self.handle_trade_loop(data[index])
888
+ else:
889
+ # in spot, chronologically increasing: 1709536771200, 1709536771226,
890
+ for i in range(0, length):
891
+ symbol = self.handle_trade_loop(data[i])
892
+ client.resolve(self.trades[symbol], 'trade:' + symbol)
893
+
894
+ def handle_trade_loop(self, entry):
895
+ trade = self.parse_ws_trade(entry)
896
+ symbol = trade['symbol']
897
+ tradesLimit = self.safe_integer(self.options, 'tradesLimit', 1000)
898
+ if self.safe_value(self.trades, symbol) is None:
899
+ self.trades[symbol] = ArrayCache(tradesLimit)
900
+ stored = self.trades[symbol]
901
+ stored.append(trade)
902
+ return symbol
903
+
904
+ def parse_ws_trade(self, trade: dict, market: Market = None):
905
+ # spot
906
+ # {
907
+ # "ms_t": 1740320841473,
908
+ # "price": "2806.54",
909
+ # "s_t": 1740320841,
910
+ # "side": "sell",
911
+ # "size": "0.77598",
912
+ # "symbol": "ETH_USDT"
913
+ # }
914
+ #
915
+ # swap
916
+ # {
917
+ # "trade_id": "3000000245258661",
918
+ # "symbol": "ETHUSDT",
919
+ # "deal_price": "2811.1",
920
+ # "deal_vol": "1858",
921
+ # "way": 2,
922
+ # "m": True,
923
+ # "created_at": "2025-02-23T13:59:59.646490751Z"
924
+ # }
925
+ #
926
+ marketId = self.safe_string(trade, 'symbol')
927
+ market = self.safe_market(marketId, market)
928
+ timestamp = self.safe_integer(trade, 'ms_t')
929
+ datetime: Str = None
930
+ if timestamp is None:
931
+ datetime = self.safe_string(trade, 'created_at')
932
+ timestamp = self.parse8601(datetime)
933
+ else:
934
+ datetime = self.iso8601(timestamp)
935
+ return self.safe_trade({
936
+ 'info': trade,
937
+ 'id': self.safe_string(trade, 'trade_id'),
938
+ 'order': None,
939
+ 'timestamp': timestamp,
940
+ 'datetime': datetime,
941
+ 'symbol': market['symbol'],
942
+ 'type': None,
943
+ 'side': self.safe_string(trade, 'side'),
944
+ 'price': self.safe_string_2(trade, 'price', 'deal_price'),
945
+ 'amount': self.safe_string_2(trade, 'size', 'deal_vol'),
946
+ 'cost': None,
947
+ 'takerOrMaker': None,
948
+ 'fee': None,
949
+ }, market)
950
+
951
+ def handle_ticker(self, client: Client, message):
952
+ #
953
+ # {
954
+ # "data": [
955
+ # {
956
+ # "base_volume_24h": "78615593.81",
957
+ # "high_24h": "52756.97",
958
+ # "last_price": "52638.31",
959
+ # "low_24h": "50991.35",
960
+ # "open_24h": "51692.03",
961
+ # "s_t": 1630981727,
962
+ # "symbol": "BTC_USDT"
963
+ # }
964
+ # ],
965
+ # "table": "spot/ticker"
966
+ # }
967
+ #
968
+ # {
969
+ # "data": {
970
+ # "symbol": "ETHUSDT",
971
+ # "last_price": "2807.73",
972
+ # "volume_24": "2227011952",
973
+ # "range": "0.0273398194664491",
974
+ # "mark_price": "2807.5",
975
+ # "index_price": "2808.71047619",
976
+ # "ask_price": "2808.04",
977
+ # "ask_vol": "7371",
978
+ # "bid_price": "2807.28",
979
+ # "bid_vol": "3561"
980
+ # },
981
+ # "group": "futures/ticker:ETHUSDT@100ms"
982
+ # }
983
+ #
984
+ self.handle_bid_ask(client, message)
985
+ table = self.safe_string(message, 'table')
986
+ isSpot = (table is not None)
987
+ rawTickers = []
988
+ if isSpot:
989
+ rawTickers = self.safe_list(message, 'data', [])
990
+ else:
991
+ rawTickers = [self.safe_value(message, 'data', {})]
992
+ if not len(rawTickers):
993
+ return
994
+ for i in range(0, len(rawTickers)):
995
+ ticker = self.parse_ticker(rawTickers[i]) if isSpot else self.parse_ws_swap_ticker(rawTickers[i])
996
+ symbol = ticker['symbol']
997
+ self.tickers[symbol] = ticker
998
+ messageHash = 'ticker:' + symbol
999
+ client.resolve(ticker, messageHash)
1000
+
1001
+ def parse_ws_swap_ticker(self, ticker, market: Market = None):
1002
+ #
1003
+ # {
1004
+ # "symbol": "ETHUSDT",
1005
+ # "last_price": "2807.73",
1006
+ # "volume_24": "2227011952",
1007
+ # "range": "0.0273398194664491",
1008
+ # "mark_price": "2807.5",
1009
+ # "index_price": "2808.71047619",
1010
+ # "ask_price": "2808.04",
1011
+ # "ask_vol": "7371",
1012
+ # "bid_price": "2807.28",
1013
+ # "bid_vol": "3561"
1014
+ # }
1015
+ #
1016
+ marketId = self.safe_string(ticker, 'symbol')
1017
+ return self.safe_ticker({
1018
+ 'symbol': self.safe_symbol(marketId, market, '', 'swap'),
1019
+ 'timestamp': None,
1020
+ 'datetime': None,
1021
+ 'high': None,
1022
+ 'low': None,
1023
+ 'bid': self.safe_string(ticker, 'bid_price'),
1024
+ 'bidVolume': self.safe_string(ticker, 'bid_vol'),
1025
+ 'ask': self.safe_string(ticker, 'ask_price'),
1026
+ 'askVolume': self.safe_string(ticker, 'ask_vol'),
1027
+ 'vwap': None,
1028
+ 'open': None,
1029
+ 'close': None,
1030
+ 'last': self.safe_string(ticker, 'last_price'),
1031
+ 'previousClose': None,
1032
+ 'change': None,
1033
+ 'percentage': None,
1034
+ 'average': None,
1035
+ 'baseVolume': None,
1036
+ 'quoteVolume': self.safe_string(ticker, 'volume_24'),
1037
+ 'info': ticker,
1038
+ 'markPrice': self.safe_string(ticker, 'mark_price'),
1039
+ 'indexPrice': self.safe_string(ticker, 'index_price'),
1040
+ }, market)
1041
+
1042
+ async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
1043
+ """
1044
+
1045
+ https://developer-pro.bitmart.com/en/spot/#public-kline-channel
1046
+ https://developer-pro.bitmart.com/en/futuresv2/#public-klinebin-channel
1047
+
1048
+ watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1049
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
1050
+ :param str timeframe: the length of time each candle represents
1051
+ :param int [since]: timestamp in ms of the earliest candle to fetch
1052
+ :param int [limit]: the maximum amount of candles to fetch
1053
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1054
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
1055
+ """
1056
+ await self.load_markets()
1057
+ symbol = self.symbol(symbol)
1058
+ market = self.market(symbol)
1059
+ type = 'spot'
1060
+ type, params = self.handle_market_type_and_params('watchOrderBook', market, params)
1061
+ timeframes = self.safe_value(self.options, 'timeframes', {})
1062
+ interval = self.safe_string(timeframes, timeframe)
1063
+ name = None
1064
+ if type == 'spot':
1065
+ name = 'kline' + interval
1066
+ else:
1067
+ name = 'klineBin' + interval
1068
+ ohlcv = await self.subscribe(name, symbol, type, params)
1069
+ if self.newUpdates:
1070
+ limit = ohlcv.getLimit(symbol, limit)
1071
+ return self.filter_by_since_limit(ohlcv, since, limit, 0, True)
1072
+
1073
+ def handle_ohlcv(self, client: Client, message):
1074
+ #
1075
+ # {
1076
+ # "data": [
1077
+ # {
1078
+ # "candle": [
1079
+ # 1631056350,
1080
+ # "46532.83",
1081
+ # "46555.71",
1082
+ # "46511.41",
1083
+ # "46555.71",
1084
+ # "0.25"
1085
+ # ],
1086
+ # "symbol": "BTC_USDT"
1087
+ # }
1088
+ # ],
1089
+ # "table": "spot/kline1m"
1090
+ # }
1091
+ # swap
1092
+ # {
1093
+ # "group":"futures/klineBin1m:BTCUSDT",
1094
+ # "data":{
1095
+ # "symbol":"BTCUSDT",
1096
+ # "items":[
1097
+ # {
1098
+ # "o":"39635.8",
1099
+ # "h":"39636",
1100
+ # "l":"39614.4",
1101
+ # "c":"39629.7",
1102
+ # "v":"31852",
1103
+ # "ts":1701617761
1104
+ # }
1105
+ # ]
1106
+ # }
1107
+ # }
1108
+ #
1109
+ channel = self.safe_string_2(message, 'table', 'group')
1110
+ isSpot = (channel.find('spot') >= 0)
1111
+ data = self.safe_value(message, 'data')
1112
+ if data is None:
1113
+ return
1114
+ parts = channel.split('/')
1115
+ part1 = self.safe_string(parts, 1, '')
1116
+ interval = part1.replace('kline', '')
1117
+ interval = interval.replace('Bin', '')
1118
+ intervalParts = interval.split(':')
1119
+ interval = self.safe_string(intervalParts, 0)
1120
+ # use a reverse lookup in a static map instead
1121
+ timeframes = self.safe_value(self.options, 'timeframes', {})
1122
+ timeframe = self.find_timeframe(interval, timeframes)
1123
+ duration = self.parse_timeframe(timeframe)
1124
+ durationInMs = duration * 1000
1125
+ if isSpot:
1126
+ for i in range(0, len(data)):
1127
+ marketId = self.safe_string(data[i], 'symbol')
1128
+ market = self.safe_market(marketId)
1129
+ symbol = market['symbol']
1130
+ rawOHLCV = self.safe_value(data[i], 'candle')
1131
+ parsed = self.parse_ohlcv(rawOHLCV, market)
1132
+ parsed[0] = self.parse_to_int(parsed[0] / durationInMs) * durationInMs
1133
+ self.ohlcvs[symbol] = self.safe_value(self.ohlcvs, symbol, {})
1134
+ stored = self.safe_value(self.ohlcvs[symbol], timeframe)
1135
+ if stored is None:
1136
+ limit = self.safe_integer(self.options, 'OHLCVLimit', 1000)
1137
+ stored = ArrayCacheByTimestamp(limit)
1138
+ self.ohlcvs[symbol][timeframe] = stored
1139
+ stored.append(parsed)
1140
+ messageHash = channel + ':' + marketId
1141
+ client.resolve(stored, messageHash)
1142
+ else:
1143
+ marketId = self.safe_string(data, 'symbol')
1144
+ market = self.safe_market(marketId, None, None, 'swap')
1145
+ symbol = market['symbol']
1146
+ items = self.safe_value(data, 'items', [])
1147
+ self.ohlcvs[symbol] = self.safe_value(self.ohlcvs, symbol, {})
1148
+ stored = self.safe_value(self.ohlcvs[symbol], timeframe)
1149
+ if stored is None:
1150
+ limit = self.safe_integer(self.options, 'OHLCVLimit', 1000)
1151
+ stored = ArrayCacheByTimestamp(limit)
1152
+ self.ohlcvs[symbol][timeframe] = stored
1153
+ for i in range(0, len(items)):
1154
+ candle = items[i]
1155
+ parsed = self.parse_ohlcv(candle, market)
1156
+ stored.append(parsed)
1157
+ client.resolve(stored, channel)
1158
+
1159
+ async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
1160
+ """
1161
+
1162
+ https://developer-pro.bitmart.com/en/spot/#public-depth-all-channel
1163
+ https://developer-pro.bitmart.com/en/spot/#public-depth-increase-channel
1164
+ https://developer-pro.bitmart.com/en/futuresv2/#public-depth-channel
1165
+
1166
+ watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
1167
+ :param str symbol: unified symbol of the market to fetch the order book for
1168
+ :param int [limit]: the maximum amount of order book entries to return
1169
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1170
+ :param str [params.speed]: *futures only* '100ms' or '200ms'
1171
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
1172
+ """
1173
+ await self.load_markets()
1174
+ options = self.safe_value(self.options, 'watchOrderBook', {})
1175
+ depth = self.safe_string(options, 'depth', 'depth/increase100')
1176
+ symbol = self.symbol(symbol)
1177
+ market = self.market(symbol)
1178
+ type = 'spot'
1179
+ type, params = self.handle_market_type_and_params('watchOrderBook', market, params)
1180
+ if type == 'swap' and depth == 'depth/increase100':
1181
+ depth = 'depth50'
1182
+ orderbook = await self.subscribe(depth, symbol, type, params)
1183
+ return orderbook.limit()
1184
+
1185
+ def handle_delta(self, bookside, delta):
1186
+ price = self.safe_float(delta, 0)
1187
+ amount = self.safe_float(delta, 1)
1188
+ bookside.store(price, amount)
1189
+
1190
+ def handle_deltas(self, bookside, deltas):
1191
+ for i in range(0, len(deltas)):
1192
+ self.handle_delta(bookside, deltas[i])
1193
+
1194
+ def handle_order_book_message(self, client: Client, message, orderbook):
1195
+ #
1196
+ # {
1197
+ # "asks": [
1198
+ # ['46828.38', "0.21847"],
1199
+ # ['46830.68', "0.08232"],
1200
+ # ['46832.08', "0.09285"],
1201
+ # ['46837.82', "0.02028"],
1202
+ # ['46839.43', "0.15068"]
1203
+ # ],
1204
+ # "bids": [
1205
+ # ['46820.78', "0.00444"],
1206
+ # ['46814.33', "0.00234"],
1207
+ # ['46813.50', "0.05021"],
1208
+ # ['46808.14', "0.00217"],
1209
+ # ['46808.04', "0.00013"]
1210
+ # ],
1211
+ # "ms_t": 1631044962431,
1212
+ # "symbol": "BTC_USDT"
1213
+ # }
1214
+ #
1215
+ asks = self.safe_list(message, 'asks', [])
1216
+ bids = self.safe_list(message, 'bids', [])
1217
+ self.handle_deltas(orderbook['asks'], asks)
1218
+ self.handle_deltas(orderbook['bids'], bids)
1219
+ timestamp = self.safe_integer(message, 'ms_t')
1220
+ marketId = self.safe_string(message, 'symbol')
1221
+ symbol = self.safe_symbol(marketId)
1222
+ orderbook['symbol'] = symbol
1223
+ orderbook['timestamp'] = timestamp
1224
+ orderbook['datetime'] = self.iso8601(timestamp)
1225
+ return orderbook
1226
+
1227
+ def handle_order_book(self, client: Client, message):
1228
+ #
1229
+ # spot depth-all
1230
+ #
1231
+ # {
1232
+ # "data": [
1233
+ # {
1234
+ # "asks": [
1235
+ # ['46828.38', "0.21847"],
1236
+ # ['46830.68', "0.08232"],
1237
+ # ...
1238
+ # ],
1239
+ # "bids": [
1240
+ # ['46820.78', "0.00444"],
1241
+ # ['46814.33', "0.00234"],
1242
+ # ...
1243
+ # ],
1244
+ # "ms_t": 1631044962431,
1245
+ # "symbol": "BTC_USDT"
1246
+ # }
1247
+ # ],
1248
+ # "table": "spot/depth5"
1249
+ # }
1250
+ #
1251
+ # spot increse depth snapshot
1252
+ #
1253
+ # {
1254
+ # "data":[
1255
+ # {
1256
+ # "asks":[
1257
+ # ["43652.52", "0.02039"],
1258
+ # ...
1259
+ # ],
1260
+ # "bids":[
1261
+ # ["43652.51", "0.00500"],
1262
+ # ...
1263
+ # ],
1264
+ # "ms_t":1703376836487,
1265
+ # "symbol":"BTC_USDT",
1266
+ # "type":"snapshot", # or update
1267
+ # "version":2141731
1268
+ # }
1269
+ # ],
1270
+ # "table":"spot/depth/increase100"
1271
+ # }
1272
+ #
1273
+ # swap
1274
+ #
1275
+ # {
1276
+ # "group":"futures/depth50:BTCUSDT",
1277
+ # "data":{
1278
+ # "symbol":"BTCUSDT",
1279
+ # "way":1,
1280
+ # "depths":[
1281
+ # {
1282
+ # "price":"39509.8",
1283
+ # "vol":"2379"
1284
+ # },
1285
+ # {
1286
+ # "price":"39509.6",
1287
+ # "vol":"6815"
1288
+ # },
1289
+ # ...
1290
+ # ],
1291
+ # "ms_t":1701566021194
1292
+ # }
1293
+ # }
1294
+ #
1295
+ isSpot = ('table' in message)
1296
+ datas = []
1297
+ if isSpot:
1298
+ datas = self.safe_list(message, 'data', datas)
1299
+ else:
1300
+ orderBookEntry = self.safe_dict(message, 'data')
1301
+ if orderBookEntry is not None:
1302
+ datas.append(orderBookEntry)
1303
+ length = len(datas)
1304
+ if length <= 0:
1305
+ return
1306
+ channelName = self.safe_string_2(message, 'table', 'group')
1307
+ # find limit subscribed to
1308
+ limitsToCheck = ['100', '50', '20', '10', '5']
1309
+ limit = 0
1310
+ for i in range(0, len(limitsToCheck)):
1311
+ limitString = limitsToCheck[i]
1312
+ if channelName.find(limitString) >= 0:
1313
+ limit = self.parse_to_int(limitString)
1314
+ break
1315
+ if isSpot:
1316
+ channel = channelName.replace('spot/', '')
1317
+ for i in range(0, len(datas)):
1318
+ update = datas[i]
1319
+ marketId = self.safe_string(update, 'symbol')
1320
+ symbol = self.safe_symbol(marketId)
1321
+ if not (symbol in self.orderbooks):
1322
+ ob = self.order_book({}, limit)
1323
+ ob['symbol'] = symbol
1324
+ self.orderbooks[symbol] = ob
1325
+ orderbook = self.orderbooks[symbol]
1326
+ type = self.safe_string(update, 'type')
1327
+ if (type == 'snapshot') or (not(channelName.find('increase') >= 0)):
1328
+ orderbook.reset({})
1329
+ self.handle_order_book_message(client, update, orderbook)
1330
+ timestamp = self.safe_integer(update, 'ms_t')
1331
+ if orderbook['timestamp'] is None:
1332
+ orderbook['timestamp'] = timestamp
1333
+ orderbook['datetime'] = self.iso8601(timestamp)
1334
+ messageHash = channelName + ':' + marketId
1335
+ client.resolve(orderbook, messageHash)
1336
+ # resolve ForSymbols
1337
+ messageHashForMulti = channel + ':' + symbol
1338
+ client.resolve(orderbook, messageHashForMulti)
1339
+ else:
1340
+ tableParts = channelName.split(':')
1341
+ channel = tableParts[0].replace('futures/', '')
1342
+ data = datas[0] # contract markets always contain only one member
1343
+ depths = data['depths']
1344
+ marketId = self.safe_string(data, 'symbol')
1345
+ symbol = self.safe_symbol(marketId)
1346
+ if not (symbol in self.orderbooks):
1347
+ ob = self.order_book({}, limit)
1348
+ ob['symbol'] = symbol
1349
+ self.orderbooks[symbol] = ob
1350
+ orderbook = self.orderbooks[symbol]
1351
+ way = self.safe_integer(data, 'way')
1352
+ side = 'bids' if (way == 1) else 'asks'
1353
+ if way == 1:
1354
+ orderbook[side] = Bids([], limit)
1355
+ else:
1356
+ orderbook[side] = Asks([], limit)
1357
+ for i in range(0, len(depths)):
1358
+ depth = depths[i]
1359
+ price = self.safe_number(depth, 'price')
1360
+ amount = self.safe_number(depth, 'vol')
1361
+ orderbookSide = self.safe_value(orderbook, side)
1362
+ orderbookSide.store(price, amount)
1363
+ bidsLength = len(orderbook['bids'])
1364
+ asksLength = len(orderbook['asks'])
1365
+ if (bidsLength == 0) or (asksLength == 0):
1366
+ return
1367
+ timestamp = self.safe_integer(data, 'ms_t')
1368
+ orderbook['timestamp'] = timestamp
1369
+ orderbook['datetime'] = self.iso8601(timestamp)
1370
+ messageHash = channelName
1371
+ client.resolve(orderbook, messageHash)
1372
+ # resolve ForSymbols
1373
+ messageHashForMulti = channel + ':' + symbol
1374
+ client.resolve(orderbook, messageHashForMulti)
1375
+
1376
+ async def watch_order_book_for_symbols(self, symbols: List[str], limit: Int = None, params={}) -> OrderBook:
1377
+ """
1378
+ watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
1379
+
1380
+ https://developer-pro.bitmart.com/en/spot/#public-depth-increase-channel
1381
+
1382
+ :param str[] symbols: unified array of symbols
1383
+ :param int [limit]: the maximum amount of order book entries to return
1384
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1385
+ :param str [params.depth]: the type of order book to subscribe to, default is 'depth/increase100', also accepts 'depth5' or 'depth20' or depth50
1386
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
1387
+ """
1388
+ await self.load_markets()
1389
+ type = None
1390
+ symbols, type, params = self.get_params_for_multiple_sub('watchOrderBookForSymbols', symbols, limit, params)
1391
+ channel = None
1392
+ channel, params = self.handle_option_and_params(params, 'watchOrderBookForSymbols', 'depth', 'depth/increase100')
1393
+ if type == 'swap' and channel == 'depth/increase100':
1394
+ channel = 'depth50'
1395
+ orderbook = await self.subscribe_multiple(channel, type, symbols, params)
1396
+ return orderbook.limit()
1397
+
1398
+ async def authenticate(self, type, params={}):
1399
+ self.check_required_credentials()
1400
+ url = self.implode_hostname(self.urls['api']['ws'][type]['private'])
1401
+ messageHash = 'authenticated'
1402
+ client = self.client(url)
1403
+ future = client.future(messageHash)
1404
+ authenticated = self.safe_value(client.subscriptions, messageHash)
1405
+ if authenticated is None:
1406
+ timestamp = str(self.milliseconds())
1407
+ memo = self.uid
1408
+ path = 'bitmart.WebSocket'
1409
+ auth = timestamp + '#' + memo + '#' + path
1410
+ signature = self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha256)
1411
+ request = None
1412
+ if type == 'spot':
1413
+ request = {
1414
+ 'op': 'login',
1415
+ 'args': [
1416
+ self.apiKey,
1417
+ timestamp,
1418
+ signature,
1419
+ ],
1420
+ }
1421
+ else:
1422
+ request = {
1423
+ 'action': 'access',
1424
+ 'args': [
1425
+ self.apiKey,
1426
+ timestamp,
1427
+ signature,
1428
+ 'web',
1429
+ ],
1430
+ }
1431
+ message = self.extend(request, params)
1432
+ self.watch(url, messageHash, message, messageHash)
1433
+ return await future
1434
+
1435
+ def handle_subscription_status(self, client: Client, message):
1436
+ #
1437
+ # {"event":"subscribe","channel":"spot/depth:BTC-USDT"}
1438
+ #
1439
+ return message
1440
+
1441
+ def handle_authenticate(self, client: Client, message):
1442
+ #
1443
+ # spot
1444
+ # {event: "login"}
1445
+ # swap
1446
+ # {action: 'access', success: True}
1447
+ #
1448
+ messageHash = 'authenticated'
1449
+ future = self.safe_value(client.futures, messageHash)
1450
+ future.resolve(True)
1451
+
1452
+ def handle_error_message(self, client: Client, message):
1453
+ #
1454
+ # {event: "error", message: "Invalid sign", errorCode: 30013}
1455
+ # {"event":"error","message":"Unrecognized request: {\"event\":\"subscribe\",\"channel\":\"spot/depth:BTC-USDT\"}","errorCode":30039}
1456
+ # {
1457
+ # action: '',
1458
+ # group: 'futures/trade:BTCUSDT',
1459
+ # success: False,
1460
+ # request: {action: '', args: ['futures/trade:BTCUSDT']},
1461
+ # error: 'Invalid action [] for group [futures/trade:BTCUSDT]'
1462
+ # }
1463
+ #
1464
+ errorCode = self.safe_string(message, 'errorCode')
1465
+ error = self.safe_string(message, 'error')
1466
+ try:
1467
+ if errorCode is not None or error is not None:
1468
+ feedback = self.id + ' ' + self.json(message)
1469
+ self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
1470
+ messageString = self.safe_value(message, 'message', error)
1471
+ self.throw_broadly_matched_exception(self.exceptions['broad'], messageString, feedback)
1472
+ action = self.safe_string(message, 'action')
1473
+ if action == 'access':
1474
+ raise AuthenticationError(feedback)
1475
+ raise ExchangeError(feedback)
1476
+ return False
1477
+ except Exception as e:
1478
+ if (isinstance(e, AuthenticationError)):
1479
+ messageHash = 'authenticated'
1480
+ client.reject(e, messageHash)
1481
+ if messageHash in client.subscriptions:
1482
+ del client.subscriptions[messageHash]
1483
+ client.reject(e)
1484
+ return True
1485
+
1486
+ def handle_message(self, client: Client, message):
1487
+ if self.handle_error_message(client, message):
1488
+ return
1489
+ #
1490
+ # {"event":"error","message":"Unrecognized request: {\"event\":\"subscribe\",\"channel\":\"spot/depth:BTC-USDT\"}","errorCode":30039}
1491
+ #
1492
+ # subscribe events on spot:
1493
+ #
1494
+ # {"event":"subscribe", "topic":"spot/kline1m:BTC_USDT"}
1495
+ #
1496
+ # subscribe on contracts:
1497
+ #
1498
+ # {"action":"subscribe", "group":"futures/klineBin1m:BTCUSDT", "success":true, "request":{"action":"subscribe", "args":["futures/klineBin1m:BTCUSDT"]}}
1499
+ #
1500
+ # regular updates - spot
1501
+ #
1502
+ # {
1503
+ # "table": "spot/depth",
1504
+ # "action": "partial",
1505
+ # "data": [
1506
+ # {
1507
+ # "instrument_id": "BTC-USDT",
1508
+ # "asks": [
1509
+ # ["5301.8", "0.03763319", "1"],
1510
+ # ["5302.4", "0.00305", "2"],
1511
+ # ],
1512
+ # "bids": [
1513
+ # ["5301.7", "0.58911427", "6"],
1514
+ # ["5301.6", "0.01222922", "4"],
1515
+ # ],
1516
+ # "timestamp": "2020-03-16T03:25:00.440Z",
1517
+ # "checksum": -2088736623
1518
+ # }
1519
+ # ]
1520
+ # }
1521
+ #
1522
+ # regular updates - contracts
1523
+ #
1524
+ # {
1525
+ # group: "futures/klineBin1m:BTCUSDT",
1526
+ # data: {
1527
+ # symbol: "BTCUSDT",
1528
+ # items: [{o: "67944.7", "h": ....}],
1529
+ # },
1530
+ # }
1531
+ #
1532
+ # {data: '', table: "spot/user/order"}
1533
+ #
1534
+ # the only realiable way(for both spot & swap) is to check 'data' key
1535
+ isDataUpdate = ('data' in message)
1536
+ if not isDataUpdate:
1537
+ event = self.safe_string_2(message, 'event', 'action')
1538
+ if event is not None:
1539
+ methods: dict = {
1540
+ # 'info': self.handleSystemStatus,
1541
+ 'login': self.handle_authenticate,
1542
+ 'access': self.handle_authenticate,
1543
+ 'subscribe': self.handle_subscription_status,
1544
+ }
1545
+ method = self.safe_value(methods, event)
1546
+ if method is not None:
1547
+ method(client, message)
1548
+ else:
1549
+ channel = self.safe_string_2(message, 'table', 'group')
1550
+ methods: dict = {
1551
+ 'depth': self.handle_order_book,
1552
+ 'ticker': self.handle_ticker,
1553
+ 'trade': self.handle_trade,
1554
+ 'kline': self.handle_ohlcv,
1555
+ 'order': self.handle_orders,
1556
+ 'position': self.handle_positions,
1557
+ 'balance': self.handle_balance,
1558
+ 'asset': self.handle_balance,
1559
+ }
1560
+ keys = list(methods.keys())
1561
+ for i in range(0, len(keys)):
1562
+ key = keys[i]
1563
+ if channel.find(key) >= 0:
1564
+ method = self.safe_value(methods, key)
1565
+ method(client, message)