bitmart 0.0.116__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.
- bitmart/__init__.py +7 -0
- bitmart/ccxt/__init__.py +102 -0
- bitmart/ccxt/abstract/bitmart.py +117 -0
- bitmart/ccxt/async_support/__init__.py +81 -0
- bitmart/ccxt/async_support/base/__init__.py +1 -0
- bitmart/ccxt/async_support/base/exchange.py +2315 -0
- bitmart/ccxt/async_support/base/throttler.py +88 -0
- bitmart/ccxt/async_support/base/ws/__init__.py +38 -0
- bitmart/ccxt/async_support/base/ws/cache.py +219 -0
- bitmart/ccxt/async_support/base/ws/client.py +350 -0
- bitmart/ccxt/async_support/base/ws/functions.py +59 -0
- bitmart/ccxt/async_support/base/ws/future.py +46 -0
- bitmart/ccxt/async_support/base/ws/order_book.py +78 -0
- bitmart/ccxt/async_support/base/ws/order_book_side.py +174 -0
- bitmart/ccxt/async_support/bitmart.py +5361 -0
- bitmart/ccxt/base/__init__.py +27 -0
- bitmart/ccxt/base/decimal_to_precision.py +178 -0
- bitmart/ccxt/base/errors.py +273 -0
- bitmart/ccxt/base/exchange.py +7642 -0
- bitmart/ccxt/base/precise.py +297 -0
- bitmart/ccxt/base/types.py +619 -0
- bitmart/ccxt/bitmart.py +5361 -0
- bitmart/ccxt/pro/__init__.py +66 -0
- bitmart/ccxt/pro/bitmart.py +1917 -0
- bitmart/ccxt/static_dependencies/README.md +1 -0
- bitmart/ccxt/static_dependencies/__init__.py +1 -0
- bitmart/ccxt/static_dependencies/bip/__init__.py +6 -0
- bitmart/ccxt/static_dependencies/bip/addr/P2PKH_addr.py +205 -0
- bitmart/ccxt/static_dependencies/bip/addr/__init__.py +5 -0
- bitmart/ccxt/static_dependencies/bip/addr/addr_dec_utils.py +125 -0
- bitmart/ccxt/static_dependencies/bip/addr/addr_key_validator.py +162 -0
- bitmart/ccxt/static_dependencies/bip/addr/iaddr_decoder.py +48 -0
- bitmart/ccxt/static_dependencies/bip/addr/iaddr_encoder.py +50 -0
- bitmart/ccxt/static_dependencies/bip/base58/__init__.py +3 -0
- bitmart/ccxt/static_dependencies/bip/base58/base58.py +207 -0
- bitmart/ccxt/static_dependencies/bip/base58/base58_ex.py +25 -0
- bitmart/ccxt/static_dependencies/bip/base58/base58_xmr.py +155 -0
- bitmart/ccxt/static_dependencies/bip/bech32/__init__.py +4 -0
- bitmart/ccxt/static_dependencies/bip/bech32/bch_bech32.py +220 -0
- bitmart/ccxt/static_dependencies/bip/bech32/bech32.py +235 -0
- bitmart/ccxt/static_dependencies/bip/bech32/bech32_base.py +246 -0
- bitmart/ccxt/static_dependencies/bip/bech32/bech32_ex.py +25 -0
- bitmart/ccxt/static_dependencies/bip/bech32/segwit_bech32.py +173 -0
- bitmart/ccxt/static_dependencies/bip/bip32/__init__.py +14 -0
- bitmart/ccxt/static_dependencies/bip/bip32/base/__init__.py +3 -0
- bitmart/ccxt/static_dependencies/bip/bip32/base/bip32_base.py +581 -0
- bitmart/ccxt/static_dependencies/bip/bip32/base/ibip32_key_derivator.py +83 -0
- bitmart/ccxt/static_dependencies/bip/bip32/base/ibip32_mst_key_generator.py +47 -0
- bitmart/ccxt/static_dependencies/bip/bip32/bip32_const.py +35 -0
- bitmart/ccxt/static_dependencies/bip/bip32/bip32_ex.py +29 -0
- bitmart/ccxt/static_dependencies/bip/bip32/bip32_key_data.py +500 -0
- bitmart/ccxt/static_dependencies/bip/bip32/bip32_key_net_ver.py +83 -0
- bitmart/ccxt/static_dependencies/bip/bip32/bip32_key_ser.py +294 -0
- bitmart/ccxt/static_dependencies/bip/bip32/bip32_keys.py +457 -0
- bitmart/ccxt/static_dependencies/bip/bip32/bip32_path.py +247 -0
- bitmart/ccxt/static_dependencies/bip/bip32/bip32_utils.py +72 -0
- bitmart/ccxt/static_dependencies/bip/bip32/kholaw/__init__.py +4 -0
- bitmart/ccxt/static_dependencies/bip/bip32/kholaw/bip32_kholaw_ed25519.py +82 -0
- bitmart/ccxt/static_dependencies/bip/bip32/kholaw/bip32_kholaw_ed25519_key_derivator.py +118 -0
- bitmart/ccxt/static_dependencies/bip/bip32/kholaw/bip32_kholaw_key_derivator_base.py +204 -0
- bitmart/ccxt/static_dependencies/bip/bip32/kholaw/bip32_kholaw_mst_key_generator.py +119 -0
- bitmart/ccxt/static_dependencies/bip/bip32/slip10/__init__.py +1 -0
- bitmart/ccxt/static_dependencies/bip/bip32/slip10/bip32_slip10_key_derivator.py +200 -0
- bitmart/ccxt/static_dependencies/bip/bip32/slip10/bip32_slip10_mst_key_generator.py +168 -0
- bitmart/ccxt/static_dependencies/bip/bip32/slip10/bip32_slip10_secp256k1.py +82 -0
- bitmart/ccxt/static_dependencies/bip/bip44/__init__.py +1 -0
- bitmart/ccxt/static_dependencies/bip/bip44/bip44.py +265 -0
- bitmart/ccxt/static_dependencies/bip/bip44_base/__init__.py +3 -0
- bitmart/ccxt/static_dependencies/bip/bip44_base/bip44_base.py +624 -0
- bitmart/ccxt/static_dependencies/bip/bip44_base/bip44_base_ex.py +25 -0
- bitmart/ccxt/static_dependencies/bip/bip44_base/bip44_keys.py +225 -0
- bitmart/ccxt/static_dependencies/bip/coin_conf/__init__.py +2 -0
- bitmart/ccxt/static_dependencies/bip/coin_conf/coin_conf.py +68 -0
- bitmart/ccxt/static_dependencies/bip/coin_conf/coins_conf.py +890 -0
- bitmart/ccxt/static_dependencies/bip/conf/__init__.py +0 -0
- bitmart/ccxt/static_dependencies/bip/conf/bip44/__init__.py +3 -0
- bitmart/ccxt/static_dependencies/bip/conf/bip44/bip44_coins.py +126 -0
- bitmart/ccxt/static_dependencies/bip/conf/bip44/bip44_conf.py +1360 -0
- bitmart/ccxt/static_dependencies/bip/conf/bip44/bip44_conf_getter.py +153 -0
- bitmart/ccxt/static_dependencies/bip/conf/bip49/__init__.py +3 -0
- bitmart/ccxt/static_dependencies/bip/conf/bip49/bip49_coins.py +53 -0
- bitmart/ccxt/static_dependencies/bip/conf/bip49/bip49_conf.py +366 -0
- bitmart/ccxt/static_dependencies/bip/conf/bip49/bip49_conf_getter.py +80 -0
- bitmart/ccxt/static_dependencies/bip/conf/bip84/__init__.py +3 -0
- bitmart/ccxt/static_dependencies/bip/conf/bip84/bip84_coins.py +39 -0
- bitmart/ccxt/static_dependencies/bip/conf/bip84/bip84_conf.py +113 -0
- bitmart/ccxt/static_dependencies/bip/conf/bip84/bip84_conf_getter.py +66 -0
- bitmart/ccxt/static_dependencies/bip/conf/bip86/__init__.py +3 -0
- bitmart/ccxt/static_dependencies/bip/conf/bip86/bip86_coins.py +37 -0
- bitmart/ccxt/static_dependencies/bip/conf/bip86/bip86_conf.py +83 -0
- bitmart/ccxt/static_dependencies/bip/conf/bip86/bip86_conf_getter.py +64 -0
- bitmart/ccxt/static_dependencies/bip/conf/common/__init__.py +8 -0
- bitmart/ccxt/static_dependencies/bip/conf/common/atom_addr.py +104 -0
- bitmart/ccxt/static_dependencies/bip/conf/common/bip_bitcoin_cash_conf.py +106 -0
- bitmart/ccxt/static_dependencies/bip/conf/common/bip_coin_conf.py +217 -0
- bitmart/ccxt/static_dependencies/bip/conf/common/bip_coins.py +28 -0
- bitmart/ccxt/static_dependencies/bip/conf/common/bip_conf_const.py +30 -0
- bitmart/ccxt/static_dependencies/bip/conf/common/bip_litecoin_conf.py +121 -0
- bitmart/ccxt/static_dependencies/bip/ecc/__init__.py +42 -0
- bitmart/ccxt/static_dependencies/bip/ecc/common/__init__.py +0 -0
- bitmart/ccxt/static_dependencies/bip/ecc/common/dummy_point.py +219 -0
- bitmart/ccxt/static_dependencies/bip/ecc/common/ikeys.py +263 -0
- bitmart/ccxt/static_dependencies/bip/ecc/common/ipoint.py +190 -0
- bitmart/ccxt/static_dependencies/bip/ecc/conf.py +28 -0
- bitmart/ccxt/static_dependencies/bip/ecc/curve/__init__.py +0 -0
- bitmart/ccxt/static_dependencies/bip/ecc/curve/elliptic_curve.py +121 -0
- bitmart/ccxt/static_dependencies/bip/ecc/curve/elliptic_curve_getter.py +74 -0
- bitmart/ccxt/static_dependencies/bip/ecc/curve/elliptic_curve_types.py +37 -0
- bitmart/ccxt/static_dependencies/bip/ecc/ecdsa/__init__.py +0 -0
- bitmart/ccxt/static_dependencies/bip/ecc/ecdsa/ecdsa_keys.py +36 -0
- bitmart/ccxt/static_dependencies/bip/ecc/secp256k1/__init__.py +0 -0
- bitmart/ccxt/static_dependencies/bip/ecc/secp256k1/secp256k1.py +36 -0
- bitmart/ccxt/static_dependencies/bip/ecc/secp256k1/secp256k1_const.py +59 -0
- bitmart/ccxt/static_dependencies/bip/ecc/secp256k1/secp256k1_keys_ecdsa.py +248 -0
- bitmart/ccxt/static_dependencies/bip/ecc/secp256k1/secp256k1_point_ecdsa.py +234 -0
- bitmart/ccxt/static_dependencies/bip/slip/__init__.py +0 -0
- bitmart/ccxt/static_dependencies/bip/slip/slip173/__init__.py +1 -0
- bitmart/ccxt/static_dependencies/bip/slip/slip173/slip173.py +60 -0
- bitmart/ccxt/static_dependencies/bip/slip/slip32/__init__.py +4 -0
- bitmart/ccxt/static_dependencies/bip/slip/slip32/slip32.py +322 -0
- bitmart/ccxt/static_dependencies/bip/slip/slip32/slip32_key_net_ver.py +62 -0
- bitmart/ccxt/static_dependencies/bip/slip/slip44/__init__.py +1 -0
- bitmart/ccxt/static_dependencies/bip/slip/slip44/slip44.py +81 -0
- bitmart/ccxt/static_dependencies/bip/utils/__init__.py +0 -0
- bitmart/ccxt/static_dependencies/bip/utils/conf/__init__.py +1 -0
- bitmart/ccxt/static_dependencies/bip/utils/conf/coin_names.py +59 -0
- bitmart/ccxt/static_dependencies/bip/utils/crypto/__init__.py +10 -0
- bitmart/ccxt/static_dependencies/bip/utils/crypto/aes_ecb.py +152 -0
- bitmart/ccxt/static_dependencies/bip/utils/crypto/blake2.py +191 -0
- bitmart/ccxt/static_dependencies/bip/utils/crypto/chacha20_poly1305.py +101 -0
- bitmart/ccxt/static_dependencies/bip/utils/crypto/hash160.py +57 -0
- bitmart/ccxt/static_dependencies/bip/utils/crypto/hmac.py +118 -0
- bitmart/ccxt/static_dependencies/bip/utils/crypto/pbkdf2.py +66 -0
- bitmart/ccxt/static_dependencies/bip/utils/crypto/ripemd.py +58 -0
- bitmart/ccxt/static_dependencies/bip/utils/crypto/scrypt.py +66 -0
- bitmart/ccxt/static_dependencies/bip/utils/crypto/sha2.py +182 -0
- bitmart/ccxt/static_dependencies/bip/utils/crypto/sha3.py +99 -0
- bitmart/ccxt/static_dependencies/bip/utils/misc/__init__.py +7 -0
- bitmart/ccxt/static_dependencies/bip/utils/misc/algo.py +108 -0
- bitmart/ccxt/static_dependencies/bip/utils/misc/base32.py +151 -0
- bitmart/ccxt/static_dependencies/bip/utils/misc/bit.py +115 -0
- bitmart/ccxt/static_dependencies/bip/utils/misc/bytes.py +200 -0
- bitmart/ccxt/static_dependencies/bip/utils/misc/data_bytes.py +181 -0
- bitmart/ccxt/static_dependencies/bip/utils/misc/integer.py +97 -0
- bitmart/ccxt/static_dependencies/bip/utils/misc/string.py +54 -0
- bitmart/ccxt/static_dependencies/bip/utils/typing/__init__.py +1 -0
- bitmart/ccxt/static_dependencies/bip/utils/typing/literal.py +27 -0
- bitmart/ccxt/static_dependencies/bip/wif/__init__.py +1 -0
- bitmart/ccxt/static_dependencies/bip/wif/wif.py +144 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/amino/amino_pb2.py +31 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/cosmos/base/v1beta1/coin_pb2.py +47 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/cosmos/crypto/multisig/keys_pb2.py +33 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/cosmos/crypto/multisig/v1beta1/multisig_pb2.py +33 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/cosmos/crypto/secp256k1/keys_pb2.py +34 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/cosmos/msg/v1/msg_pb2.py +27 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/cosmos/tx/signing/v1beta1/signing_pb2.py +38 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/cosmos/tx/v1beta1/tx_pb2.py +75 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/cosmos_proto/cosmos_pb2.py +36 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/accountplus/accountplus_pb2.py +31 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/accountplus/genesis_pb2.py +40 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/accountplus/models_pb2.py +26 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/accountplus/params_pb2.py +29 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/accountplus/query_pb2.py +57 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/accountplus/tx_pb2.py +51 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/block_rate_limit_config_pb2.py +37 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/clob_pair_pb2.py +41 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/equity_tier_limit_config_pb2.py +35 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/finalize_block_pb2.py +27 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/liquidations_config_pb2.py +39 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/liquidations_pb2.py +38 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/matches_pb2.py +55 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/mev_pb2.py +49 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/operation_pb2.py +32 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/order_pb2.py +86 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/order_removals_pb2.py +32 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/process_proposer_matches_events_pb2.py +42 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/query_pb2.py +124 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/streaming_pb2.py +29 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/tx_pb2.py +117 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/sending/genesis_pb2.py +26 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/sending/query_pb2.py +26 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/sending/transfer_pb2.py +61 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/sending/tx_pb2.py +37 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/subaccounts/asset_position_pb2.py +29 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/subaccounts/genesis_pb2.py +30 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/subaccounts/perpetual_position_pb2.py +33 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/subaccounts/query_pb2.py +63 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/subaccounts/streaming_pb2.py +31 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/subaccounts/subaccount_pb2.py +33 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/gogoproto/gogo_pb2.py +102 -0
- bitmart/ccxt/static_dependencies/dydx_v4_client/registry.py +38 -0
- bitmart/ccxt/static_dependencies/ecdsa/__init__.py +14 -0
- bitmart/ccxt/static_dependencies/ecdsa/_version.py +520 -0
- bitmart/ccxt/static_dependencies/ecdsa/curves.py +56 -0
- bitmart/ccxt/static_dependencies/ecdsa/der.py +221 -0
- bitmart/ccxt/static_dependencies/ecdsa/ecdsa.py +310 -0
- bitmart/ccxt/static_dependencies/ecdsa/ellipticcurve.py +1039 -0
- bitmart/ccxt/static_dependencies/ecdsa/keys.py +343 -0
- bitmart/ccxt/static_dependencies/ecdsa/numbertheory.py +531 -0
- bitmart/ccxt/static_dependencies/ecdsa/rfc6979.py +100 -0
- bitmart/ccxt/static_dependencies/ecdsa/util.py +266 -0
- bitmart/ccxt/static_dependencies/ethereum/__init__.py +7 -0
- bitmart/ccxt/static_dependencies/ethereum/abi/__init__.py +16 -0
- bitmart/ccxt/static_dependencies/ethereum/abi/abi.py +19 -0
- bitmart/ccxt/static_dependencies/ethereum/abi/base.py +152 -0
- bitmart/ccxt/static_dependencies/ethereum/abi/codec.py +217 -0
- bitmart/ccxt/static_dependencies/ethereum/abi/constants.py +3 -0
- bitmart/ccxt/static_dependencies/ethereum/abi/decoding.py +565 -0
- bitmart/ccxt/static_dependencies/ethereum/abi/encoding.py +720 -0
- bitmart/ccxt/static_dependencies/ethereum/abi/exceptions.py +139 -0
- bitmart/ccxt/static_dependencies/ethereum/abi/grammar.py +443 -0
- bitmart/ccxt/static_dependencies/ethereum/abi/packed.py +13 -0
- bitmart/ccxt/static_dependencies/ethereum/abi/py.typed +0 -0
- bitmart/ccxt/static_dependencies/ethereum/abi/registry.py +643 -0
- bitmart/ccxt/static_dependencies/ethereum/abi/tools/__init__.py +3 -0
- bitmart/ccxt/static_dependencies/ethereum/abi/tools/_strategies.py +230 -0
- bitmart/ccxt/static_dependencies/ethereum/abi/utils/__init__.py +0 -0
- bitmart/ccxt/static_dependencies/ethereum/abi/utils/numeric.py +83 -0
- bitmart/ccxt/static_dependencies/ethereum/abi/utils/padding.py +27 -0
- bitmart/ccxt/static_dependencies/ethereum/abi/utils/string.py +19 -0
- bitmart/ccxt/static_dependencies/ethereum/account/__init__.py +3 -0
- bitmart/ccxt/static_dependencies/ethereum/account/encode_typed_data/__init__.py +4 -0
- bitmart/ccxt/static_dependencies/ethereum/account/encode_typed_data/encoding_and_hashing.py +239 -0
- bitmart/ccxt/static_dependencies/ethereum/account/encode_typed_data/helpers.py +40 -0
- bitmart/ccxt/static_dependencies/ethereum/account/messages.py +263 -0
- bitmart/ccxt/static_dependencies/ethereum/account/py.typed +0 -0
- bitmart/ccxt/static_dependencies/ethereum/hexbytes/__init__.py +5 -0
- bitmart/ccxt/static_dependencies/ethereum/hexbytes/_utils.py +54 -0
- bitmart/ccxt/static_dependencies/ethereum/hexbytes/main.py +65 -0
- bitmart/ccxt/static_dependencies/ethereum/hexbytes/py.typed +0 -0
- bitmart/ccxt/static_dependencies/ethereum/typing/__init__.py +63 -0
- bitmart/ccxt/static_dependencies/ethereum/typing/abi.py +6 -0
- bitmart/ccxt/static_dependencies/ethereum/typing/bls.py +7 -0
- bitmart/ccxt/static_dependencies/ethereum/typing/discovery.py +5 -0
- bitmart/ccxt/static_dependencies/ethereum/typing/encoding.py +7 -0
- bitmart/ccxt/static_dependencies/ethereum/typing/enums.py +17 -0
- bitmart/ccxt/static_dependencies/ethereum/typing/ethpm.py +9 -0
- bitmart/ccxt/static_dependencies/ethereum/typing/evm.py +20 -0
- bitmart/ccxt/static_dependencies/ethereum/typing/networks.py +1122 -0
- bitmart/ccxt/static_dependencies/ethereum/typing/py.typed +0 -0
- bitmart/ccxt/static_dependencies/ethereum/utils/__init__.py +115 -0
- bitmart/ccxt/static_dependencies/ethereum/utils/abi.py +72 -0
- bitmart/ccxt/static_dependencies/ethereum/utils/address.py +171 -0
- bitmart/ccxt/static_dependencies/ethereum/utils/applicators.py +151 -0
- bitmart/ccxt/static_dependencies/ethereum/utils/conversions.py +190 -0
- bitmart/ccxt/static_dependencies/ethereum/utils/currency.py +107 -0
- bitmart/ccxt/static_dependencies/ethereum/utils/curried/__init__.py +269 -0
- bitmart/ccxt/static_dependencies/ethereum/utils/debug.py +20 -0
- bitmart/ccxt/static_dependencies/ethereum/utils/decorators.py +132 -0
- bitmart/ccxt/static_dependencies/ethereum/utils/encoding.py +6 -0
- bitmart/ccxt/static_dependencies/ethereum/utils/exceptions.py +4 -0
- bitmart/ccxt/static_dependencies/ethereum/utils/functional.py +75 -0
- bitmart/ccxt/static_dependencies/ethereum/utils/hexadecimal.py +74 -0
- bitmart/ccxt/static_dependencies/ethereum/utils/humanize.py +188 -0
- bitmart/ccxt/static_dependencies/ethereum/utils/logging.py +159 -0
- bitmart/ccxt/static_dependencies/ethereum/utils/module_loading.py +31 -0
- bitmart/ccxt/static_dependencies/ethereum/utils/numeric.py +43 -0
- bitmart/ccxt/static_dependencies/ethereum/utils/py.typed +0 -0
- bitmart/ccxt/static_dependencies/ethereum/utils/toolz.py +76 -0
- bitmart/ccxt/static_dependencies/ethereum/utils/types.py +54 -0
- bitmart/ccxt/static_dependencies/ethereum/utils/typing/__init__.py +18 -0
- bitmart/ccxt/static_dependencies/ethereum/utils/typing/misc.py +14 -0
- bitmart/ccxt/static_dependencies/ethereum/utils/units.py +31 -0
- bitmart/ccxt/static_dependencies/keccak/__init__.py +3 -0
- bitmart/ccxt/static_dependencies/keccak/keccak.py +197 -0
- bitmart/ccxt/static_dependencies/lark/__init__.py +38 -0
- bitmart/ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
- bitmart/ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
- bitmart/ccxt/static_dependencies/lark/ast_utils.py +59 -0
- bitmart/ccxt/static_dependencies/lark/common.py +86 -0
- bitmart/ccxt/static_dependencies/lark/exceptions.py +292 -0
- bitmart/ccxt/static_dependencies/lark/grammar.py +130 -0
- bitmart/ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
- bitmart/ccxt/static_dependencies/lark/grammars/common.lark +59 -0
- bitmart/ccxt/static_dependencies/lark/grammars/lark.lark +62 -0
- bitmart/ccxt/static_dependencies/lark/grammars/python.lark +302 -0
- bitmart/ccxt/static_dependencies/lark/grammars/unicode.lark +7 -0
- bitmart/ccxt/static_dependencies/lark/indenter.py +143 -0
- bitmart/ccxt/static_dependencies/lark/lark.py +658 -0
- bitmart/ccxt/static_dependencies/lark/lexer.py +678 -0
- bitmart/ccxt/static_dependencies/lark/load_grammar.py +1428 -0
- bitmart/ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
- bitmart/ccxt/static_dependencies/lark/parser_frontends.py +257 -0
- bitmart/ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
- bitmart/ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
- bitmart/ccxt/static_dependencies/lark/parsers/earley.py +314 -0
- bitmart/ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
- bitmart/ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
- bitmart/ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
- bitmart/ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
- bitmart/ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
- bitmart/ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
- bitmart/ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
- bitmart/ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
- bitmart/ccxt/static_dependencies/lark/py.typed +0 -0
- bitmart/ccxt/static_dependencies/lark/reconstruct.py +107 -0
- bitmart/ccxt/static_dependencies/lark/tools/__init__.py +70 -0
- bitmart/ccxt/static_dependencies/lark/tools/nearley.py +202 -0
- bitmart/ccxt/static_dependencies/lark/tools/serialize.py +32 -0
- bitmart/ccxt/static_dependencies/lark/tools/standalone.py +196 -0
- bitmart/ccxt/static_dependencies/lark/tree.py +267 -0
- bitmart/ccxt/static_dependencies/lark/tree_matcher.py +186 -0
- bitmart/ccxt/static_dependencies/lark/tree_templates.py +180 -0
- bitmart/ccxt/static_dependencies/lark/utils.py +343 -0
- bitmart/ccxt/static_dependencies/lark/visitors.py +596 -0
- bitmart/ccxt/static_dependencies/marshmallow/__init__.py +81 -0
- bitmart/ccxt/static_dependencies/marshmallow/base.py +65 -0
- bitmart/ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
- bitmart/ccxt/static_dependencies/marshmallow/decorators.py +231 -0
- bitmart/ccxt/static_dependencies/marshmallow/error_store.py +60 -0
- bitmart/ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
- bitmart/ccxt/static_dependencies/marshmallow/fields.py +2114 -0
- bitmart/ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
- bitmart/ccxt/static_dependencies/marshmallow/py.typed +0 -0
- bitmart/ccxt/static_dependencies/marshmallow/schema.py +1228 -0
- bitmart/ccxt/static_dependencies/marshmallow/types.py +12 -0
- bitmart/ccxt/static_dependencies/marshmallow/utils.py +378 -0
- bitmart/ccxt/static_dependencies/marshmallow/validate.py +678 -0
- bitmart/ccxt/static_dependencies/marshmallow/warnings.py +2 -0
- bitmart/ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
- bitmart/ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
- bitmart/ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
- bitmart/ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
- bitmart/ccxt/static_dependencies/marshmallow_dataclass/py.typed +0 -0
- bitmart/ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
- bitmart/ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
- bitmart/ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
- bitmart/ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
- bitmart/ccxt/static_dependencies/marshmallow_oneofschema/py.typed +0 -0
- bitmart/ccxt/static_dependencies/mnemonic/__init__.py +4 -0
- bitmart/ccxt/static_dependencies/mnemonic/mnemonic.py +282 -0
- bitmart/ccxt/static_dependencies/mnemonic/py.typed +1 -0
- bitmart/ccxt/static_dependencies/mnemonic/wordlist/chinese_simplified.txt +2048 -0
- bitmart/ccxt/static_dependencies/mnemonic/wordlist/chinese_traditional.txt +2048 -0
- bitmart/ccxt/static_dependencies/mnemonic/wordlist/czech.txt +2048 -0
- bitmart/ccxt/static_dependencies/mnemonic/wordlist/english.txt +2048 -0
- bitmart/ccxt/static_dependencies/mnemonic/wordlist/french.txt +2048 -0
- bitmart/ccxt/static_dependencies/mnemonic/wordlist/italian.txt +2048 -0
- bitmart/ccxt/static_dependencies/mnemonic/wordlist/japanese.txt +2048 -0
- bitmart/ccxt/static_dependencies/mnemonic/wordlist/korean.txt +2048 -0
- bitmart/ccxt/static_dependencies/mnemonic/wordlist/portuguese.txt +2048 -0
- bitmart/ccxt/static_dependencies/mnemonic/wordlist/russian.txt +2048 -0
- bitmart/ccxt/static_dependencies/mnemonic/wordlist/spanish.txt +2048 -0
- bitmart/ccxt/static_dependencies/mnemonic/wordlist/turkish.txt +2048 -0
- bitmart/ccxt/static_dependencies/msgpack/__init__.py +55 -0
- bitmart/ccxt/static_dependencies/msgpack/_cmsgpack.pyx +11 -0
- bitmart/ccxt/static_dependencies/msgpack/_packer.pyx +374 -0
- bitmart/ccxt/static_dependencies/msgpack/_unpacker.pyx +547 -0
- bitmart/ccxt/static_dependencies/msgpack/buff_converter.h +8 -0
- bitmart/ccxt/static_dependencies/msgpack/exceptions.py +48 -0
- bitmart/ccxt/static_dependencies/msgpack/ext.py +168 -0
- bitmart/ccxt/static_dependencies/msgpack/fallback.py +951 -0
- bitmart/ccxt/static_dependencies/msgpack/pack.h +89 -0
- bitmart/ccxt/static_dependencies/msgpack/pack_template.h +820 -0
- bitmart/ccxt/static_dependencies/msgpack/sysdep.h +194 -0
- bitmart/ccxt/static_dependencies/msgpack/unpack.h +391 -0
- bitmart/ccxt/static_dependencies/msgpack/unpack_define.h +95 -0
- bitmart/ccxt/static_dependencies/msgpack/unpack_template.h +464 -0
- bitmart/ccxt/static_dependencies/parsimonious/__init__.py +10 -0
- bitmart/ccxt/static_dependencies/parsimonious/exceptions.py +105 -0
- bitmart/ccxt/static_dependencies/parsimonious/expressions.py +479 -0
- bitmart/ccxt/static_dependencies/parsimonious/grammar.py +487 -0
- bitmart/ccxt/static_dependencies/parsimonious/nodes.py +325 -0
- bitmart/ccxt/static_dependencies/parsimonious/utils.py +40 -0
- bitmart/ccxt/static_dependencies/starknet/__init__.py +0 -0
- bitmart/ccxt/static_dependencies/starknet/abi/v0/__init__.py +2 -0
- bitmart/ccxt/static_dependencies/starknet/abi/v0/model.py +44 -0
- bitmart/ccxt/static_dependencies/starknet/abi/v0/parser.py +216 -0
- bitmart/ccxt/static_dependencies/starknet/abi/v0/schemas.py +72 -0
- bitmart/ccxt/static_dependencies/starknet/abi/v0/shape.py +63 -0
- bitmart/ccxt/static_dependencies/starknet/abi/v1/__init__.py +2 -0
- bitmart/ccxt/static_dependencies/starknet/abi/v1/core_structures.json +14 -0
- bitmart/ccxt/static_dependencies/starknet/abi/v1/model.py +39 -0
- bitmart/ccxt/static_dependencies/starknet/abi/v1/parser.py +220 -0
- bitmart/ccxt/static_dependencies/starknet/abi/v1/parser_transformer.py +179 -0
- bitmart/ccxt/static_dependencies/starknet/abi/v1/schemas.py +66 -0
- bitmart/ccxt/static_dependencies/starknet/abi/v1/shape.py +47 -0
- bitmart/ccxt/static_dependencies/starknet/abi/v2/__init__.py +2 -0
- bitmart/ccxt/static_dependencies/starknet/abi/v2/model.py +89 -0
- bitmart/ccxt/static_dependencies/starknet/abi/v2/parser.py +293 -0
- bitmart/ccxt/static_dependencies/starknet/abi/v2/parser_transformer.py +192 -0
- bitmart/ccxt/static_dependencies/starknet/abi/v2/schemas.py +132 -0
- bitmart/ccxt/static_dependencies/starknet/abi/v2/shape.py +107 -0
- bitmart/ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
- bitmart/ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
- bitmart/ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
- bitmart/ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
- bitmart/ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
- bitmart/ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
- bitmart/ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
- bitmart/ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
- bitmart/ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
- bitmart/ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
- bitmart/ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
- bitmart/ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
- bitmart/ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
- bitmart/ccxt/static_dependencies/starknet/common.py +15 -0
- bitmart/ccxt/static_dependencies/starknet/constants.py +39 -0
- bitmart/ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
- bitmart/ccxt/static_dependencies/starknet/hash/address.py +79 -0
- bitmart/ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
- bitmart/ccxt/static_dependencies/starknet/hash/selector.py +16 -0
- bitmart/ccxt/static_dependencies/starknet/hash/storage.py +12 -0
- bitmart/ccxt/static_dependencies/starknet/hash/utils.py +78 -0
- bitmart/ccxt/static_dependencies/starknet/models/__init__.py +0 -0
- bitmart/ccxt/static_dependencies/starknet/models/typed_data.py +45 -0
- bitmart/ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
- bitmart/ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
- bitmart/ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
- bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
- bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
- bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
- bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
- bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
- bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
- bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
- bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
- bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
- bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
- bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
- bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
- bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
- bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
- bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
- bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
- bitmart/ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
- bitmart/ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
- bitmart/ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
- bitmart/ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
- bitmart/ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
- bitmart/ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
- bitmart/ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
- bitmart/ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
- bitmart/ccxt/static_dependencies/starknet/utils/schema.py +13 -0
- bitmart/ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
- bitmart/ccxt/static_dependencies/starkware/__init__.py +0 -0
- bitmart/ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
- bitmart/ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +50 -0
- bitmart/ccxt/static_dependencies/starkware/crypto/math_utils.py +78 -0
- bitmart/ccxt/static_dependencies/starkware/crypto/signature.py +2344 -0
- bitmart/ccxt/static_dependencies/starkware/crypto/utils.py +63 -0
- bitmart/ccxt/static_dependencies/sympy/__init__.py +0 -0
- bitmart/ccxt/static_dependencies/sympy/core/__init__.py +0 -0
- bitmart/ccxt/static_dependencies/sympy/core/intfunc.py +35 -0
- bitmart/ccxt/static_dependencies/sympy/external/__init__.py +0 -0
- bitmart/ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
- bitmart/ccxt/static_dependencies/sympy/external/importtools.py +187 -0
- bitmart/ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
- bitmart/ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
- bitmart/ccxt/static_dependencies/toolz/__init__.py +26 -0
- bitmart/ccxt/static_dependencies/toolz/_signatures.py +784 -0
- bitmart/ccxt/static_dependencies/toolz/_version.py +520 -0
- bitmart/ccxt/static_dependencies/toolz/compatibility.py +30 -0
- bitmart/ccxt/static_dependencies/toolz/curried/__init__.py +101 -0
- bitmart/ccxt/static_dependencies/toolz/curried/exceptions.py +22 -0
- bitmart/ccxt/static_dependencies/toolz/curried/operator.py +22 -0
- bitmart/ccxt/static_dependencies/toolz/dicttoolz.py +339 -0
- bitmart/ccxt/static_dependencies/toolz/functoolz.py +1049 -0
- bitmart/ccxt/static_dependencies/toolz/itertoolz.py +1057 -0
- bitmart/ccxt/static_dependencies/toolz/recipes.py +46 -0
- bitmart/ccxt/static_dependencies/toolz/utils.py +9 -0
- bitmart/ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
- bitmart/ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
- bitmart-0.0.116.dist-info/METADATA +342 -0
- bitmart-0.0.116.dist-info/RECORD +466 -0
- bitmart-0.0.116.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import collections
|
|
3
|
+
from time import time
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Throttler:
|
|
7
|
+
def __init__(self, config, loop=None):
|
|
8
|
+
self.loop = loop
|
|
9
|
+
self.config = {
|
|
10
|
+
'refillRate': 1.0, # leaky bucket refill rate in tokens per second
|
|
11
|
+
'delay': 0.001, # leaky bucket seconds before checking the queue after waiting
|
|
12
|
+
'capacity': 1.0, # leaky bucket
|
|
13
|
+
'tokens': 0, # leaky bucket
|
|
14
|
+
'cost': 1.0, # leaky bucket and rolling window
|
|
15
|
+
'algorithm': 'leakyBucket',
|
|
16
|
+
'windowSize': 60000.0, # rolling window size in milliseconds
|
|
17
|
+
'maxWeight': 0.0, # rolling window - rollingWindowSize / rateLimit // ms_of_window / ms_of_rate_limit
|
|
18
|
+
}
|
|
19
|
+
self.config.update(config)
|
|
20
|
+
if self.config['algorithm'] != 'leakyBucket':
|
|
21
|
+
self.config['maxWeight'] = self.config['windowSize'] / self.config['rateLimit']
|
|
22
|
+
self.queue = collections.deque()
|
|
23
|
+
self.running = False
|
|
24
|
+
self.timestamps = []
|
|
25
|
+
|
|
26
|
+
async def leaky_bucket_loop(self):
|
|
27
|
+
last_timestamp = time() * 1000
|
|
28
|
+
while self.running:
|
|
29
|
+
future, cost = self.queue[0]
|
|
30
|
+
cost = self.config['cost'] if cost is None else cost
|
|
31
|
+
if self.config['tokens'] >= 0:
|
|
32
|
+
self.config['tokens'] -= cost
|
|
33
|
+
if not future.done():
|
|
34
|
+
future.set_result(None)
|
|
35
|
+
self.queue.popleft()
|
|
36
|
+
# context switch
|
|
37
|
+
await asyncio.sleep(0)
|
|
38
|
+
if len(self.queue) == 0:
|
|
39
|
+
self.running = False
|
|
40
|
+
else:
|
|
41
|
+
await asyncio.sleep(self.config['delay'])
|
|
42
|
+
now = time() * 1000
|
|
43
|
+
elapsed = now - last_timestamp
|
|
44
|
+
last_timestamp = now
|
|
45
|
+
self.config['tokens'] = min(self.config['tokens'] + elapsed * self.config['refillRate'], self.config['capacity'])
|
|
46
|
+
|
|
47
|
+
async def rolling_window_loop(self):
|
|
48
|
+
while self.running:
|
|
49
|
+
future, cost = self.queue[0]
|
|
50
|
+
cost = self.config['cost'] if cost is None else cost
|
|
51
|
+
now = time() * 1000
|
|
52
|
+
cutoffTime = now - self.config['windowSize']
|
|
53
|
+
totalCost = 0
|
|
54
|
+
# Remove expired timestamps & sum the remaining requests
|
|
55
|
+
timestamps = []
|
|
56
|
+
for t in self.timestamps:
|
|
57
|
+
if t['timestamp'] > cutoffTime:
|
|
58
|
+
totalCost += t['cost']
|
|
59
|
+
timestamps.append(t)
|
|
60
|
+
self.timestamps = timestamps
|
|
61
|
+
# handle current request
|
|
62
|
+
if totalCost + cost <= self.config['maxWeight']:
|
|
63
|
+
self.timestamps.append({'timestamp': now, 'cost': cost})
|
|
64
|
+
if not future.done():
|
|
65
|
+
future.set_result(None)
|
|
66
|
+
self.queue.popleft()
|
|
67
|
+
# context switch
|
|
68
|
+
await asyncio.sleep(0)
|
|
69
|
+
if not self.queue:
|
|
70
|
+
self.running = False
|
|
71
|
+
else:
|
|
72
|
+
wait_time = (self.timestamps[0]['timestamp'] + self.config['windowSize']) - now
|
|
73
|
+
if wait_time > 0:
|
|
74
|
+
await asyncio.sleep(wait_time / 1000)
|
|
75
|
+
|
|
76
|
+
async def looper(self):
|
|
77
|
+
if self.config['algorithm'] == 'leakyBucket':
|
|
78
|
+
await self.leaky_bucket_loop()
|
|
79
|
+
else:
|
|
80
|
+
await self.rolling_window_loop()
|
|
81
|
+
|
|
82
|
+
def __call__(self, cost=None):
|
|
83
|
+
future = asyncio.Future()
|
|
84
|
+
self.queue.append((future, cost))
|
|
85
|
+
if not self.running:
|
|
86
|
+
self.running = True
|
|
87
|
+
asyncio.ensure_future(self.looper(), loop=self.loop)
|
|
88
|
+
return future
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from ccxt.base import errors
|
|
4
|
+
|
|
5
|
+
# -----------------------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
from ccxt.base import decimal_to_precision
|
|
8
|
+
|
|
9
|
+
from ccxt import BaseError # noqa: F401
|
|
10
|
+
from ccxt import ExchangeError # noqa: F401
|
|
11
|
+
from ccxt import NotSupported # noqa: F401
|
|
12
|
+
from ccxt import AuthenticationError # noqa: F401
|
|
13
|
+
from ccxt import PermissionDenied # noqa: F401
|
|
14
|
+
from ccxt import AccountSuspended # noqa: F401
|
|
15
|
+
from ccxt import InvalidNonce # noqa: F401
|
|
16
|
+
from ccxt import InsufficientFunds # noqa: F401
|
|
17
|
+
from ccxt import InvalidOrder # noqa: F401
|
|
18
|
+
from ccxt import OrderNotFound # noqa: F401
|
|
19
|
+
from ccxt import OrderNotCached # noqa: F401
|
|
20
|
+
from ccxt import DuplicateOrderId # noqa: F401
|
|
21
|
+
from ccxt import CancelPending # noqa: F401
|
|
22
|
+
from ccxt import NetworkError # noqa: F401
|
|
23
|
+
from ccxt import DDoSProtection # noqa: F401
|
|
24
|
+
from ccxt import RateLimitExceeded # noqa: F401
|
|
25
|
+
from ccxt import RequestTimeout # noqa: F401
|
|
26
|
+
from ccxt import ExchangeNotAvailable # noqa: F401
|
|
27
|
+
from ccxt import OnMaintenance # noqa: F401
|
|
28
|
+
from ccxt import InvalidAddress # noqa: F401
|
|
29
|
+
from ccxt import AddressPending # noqa: F401
|
|
30
|
+
from ccxt import ArgumentsRequired # noqa: F401
|
|
31
|
+
from ccxt import BadRequest # noqa: F401
|
|
32
|
+
from ccxt import BadResponse # noqa: F401
|
|
33
|
+
from ccxt import NullResponse # noqa: F401
|
|
34
|
+
from ccxt import OrderImmediatelyFillable # noqa: F401
|
|
35
|
+
from ccxt import OrderNotFillable # noqa: F401
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
__all__ = decimal_to_precision.__all__ + errors.__all__ # noqa: F405
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import collections
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
logger = logging.getLogger(__name__)
|
|
5
|
+
|
|
6
|
+
class Delegate:
|
|
7
|
+
def __init__(self, name, delegated):
|
|
8
|
+
self.name = name
|
|
9
|
+
self.delegated = delegated
|
|
10
|
+
|
|
11
|
+
def __get__(self, instance, owner):
|
|
12
|
+
deque = getattr(instance, self.delegated)
|
|
13
|
+
return getattr(deque, self.name)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BaseCache(list):
|
|
17
|
+
# implicitly called magic methods don't invoke __getattribute__
|
|
18
|
+
# https://docs.python.org/3/reference/datamodel.html#special-method-lookup
|
|
19
|
+
# all method lookups obey the descriptor protocol
|
|
20
|
+
# this is how the implicit api is defined in ccxt
|
|
21
|
+
__iter__ = Delegate('__iter__', '_deque')
|
|
22
|
+
__setitem__ = Delegate('__setitem__', '_deque')
|
|
23
|
+
__delitem__ = Delegate('__delitem__', '_deque')
|
|
24
|
+
__len__ = Delegate('__len__', '_deque')
|
|
25
|
+
__contains__ = Delegate('__contains__', '_deque')
|
|
26
|
+
__reversed__ = Delegate('__reversed__', '_deque')
|
|
27
|
+
clear = Delegate('clear', '_deque')
|
|
28
|
+
pop = Delegate('pop', '_deque')
|
|
29
|
+
|
|
30
|
+
def __init__(self, max_size=None):
|
|
31
|
+
super(BaseCache, self).__init__()
|
|
32
|
+
self.max_size = max_size
|
|
33
|
+
self._deque = collections.deque([], max_size)
|
|
34
|
+
|
|
35
|
+
def __eq__(self, other):
|
|
36
|
+
return list(self) == other
|
|
37
|
+
|
|
38
|
+
def __repr__(self):
|
|
39
|
+
return str(list(self))
|
|
40
|
+
|
|
41
|
+
def __add__(self, other):
|
|
42
|
+
return list(self) + other
|
|
43
|
+
|
|
44
|
+
def __getitem__(self, item):
|
|
45
|
+
# deque doesn't support slicing
|
|
46
|
+
deque = super(list, self).__getattribute__('_deque')
|
|
47
|
+
if isinstance(item, slice):
|
|
48
|
+
start, stop, step = item.indices(len(deque))
|
|
49
|
+
return [deque[i] for i in range(start, stop, step)]
|
|
50
|
+
else:
|
|
51
|
+
return deque[item]
|
|
52
|
+
|
|
53
|
+
# to be overriden
|
|
54
|
+
def getLimit(self, symbol, limit):
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
# support transpiled snake_case calls
|
|
58
|
+
def get_limit(self, symbol, limit):
|
|
59
|
+
return self.getLimit(symbol, limit)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class ArrayCache(BaseCache):
|
|
63
|
+
def __init__(self, max_size=None):
|
|
64
|
+
super(ArrayCache, self).__init__(max_size)
|
|
65
|
+
self.hashmap = {}
|
|
66
|
+
self._nested_new_updates_by_symbol = False
|
|
67
|
+
self._new_updates_by_symbol = {}
|
|
68
|
+
self._clear_updates_by_symbol = {}
|
|
69
|
+
self._all_new_updates = 0
|
|
70
|
+
self._clear_all_updates = False
|
|
71
|
+
|
|
72
|
+
def getLimit(self, symbol, limit):
|
|
73
|
+
if symbol is None:
|
|
74
|
+
new_updates_value = self._all_new_updates
|
|
75
|
+
self._clear_all_updates = True
|
|
76
|
+
else:
|
|
77
|
+
new_updates_value = self._new_updates_by_symbol.get(symbol)
|
|
78
|
+
if new_updates_value is not None and self._nested_new_updates_by_symbol:
|
|
79
|
+
new_updates_value = len(new_updates_value)
|
|
80
|
+
self._clear_updates_by_symbol[symbol] = True
|
|
81
|
+
|
|
82
|
+
if new_updates_value is None:
|
|
83
|
+
return limit
|
|
84
|
+
elif limit is not None:
|
|
85
|
+
return min(new_updates_value, limit)
|
|
86
|
+
else:
|
|
87
|
+
return new_updates_value
|
|
88
|
+
|
|
89
|
+
def append(self, item):
|
|
90
|
+
self._deque.append(item)
|
|
91
|
+
if self._clear_all_updates:
|
|
92
|
+
self._clear_all_updates = False
|
|
93
|
+
self._clear_updates_by_symbol.clear()
|
|
94
|
+
self._all_new_updates = 0
|
|
95
|
+
self._new_updates_by_symbol.clear()
|
|
96
|
+
if self._clear_updates_by_symbol.get(item['symbol']):
|
|
97
|
+
self._clear_updates_by_symbol[item['symbol']] = False
|
|
98
|
+
self._new_updates_by_symbol[item['symbol']] = 0
|
|
99
|
+
self._new_updates_by_symbol[item['symbol']] = self._new_updates_by_symbol.get(item['symbol'], 0) + 1
|
|
100
|
+
self._all_new_updates = (self._all_new_updates or 0) + 1
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class ArrayCacheByTimestamp(BaseCache):
|
|
104
|
+
def __init__(self, max_size=None):
|
|
105
|
+
super(ArrayCacheByTimestamp, self).__init__(max_size)
|
|
106
|
+
self.hashmap = {}
|
|
107
|
+
self._size_tracker = set()
|
|
108
|
+
self._new_updates = 0
|
|
109
|
+
self._clear_updates = False
|
|
110
|
+
|
|
111
|
+
def getLimit(self, symbol, limit):
|
|
112
|
+
self._clear_updates = True
|
|
113
|
+
if limit is None:
|
|
114
|
+
return self._new_updates
|
|
115
|
+
return min(self._new_updates, limit)
|
|
116
|
+
|
|
117
|
+
def append(self, item):
|
|
118
|
+
if item[0] in self.hashmap:
|
|
119
|
+
reference = self.hashmap[item[0]]
|
|
120
|
+
if reference != item:
|
|
121
|
+
reference[0:len(item)] = item
|
|
122
|
+
else:
|
|
123
|
+
self.hashmap[item[0]] = item
|
|
124
|
+
if len(self._deque) == self._deque.maxlen:
|
|
125
|
+
delete_reference = self._deque.popleft()
|
|
126
|
+
del self.hashmap[delete_reference[0]]
|
|
127
|
+
self._deque.append(item)
|
|
128
|
+
if self._clear_updates:
|
|
129
|
+
self._clear_updates = False
|
|
130
|
+
self._size_tracker.clear()
|
|
131
|
+
self._size_tracker.add(item[0])
|
|
132
|
+
self._new_updates = len(self._size_tracker)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class ArrayCacheBySymbolById(ArrayCache):
|
|
136
|
+
def __init__(self, max_size=None):
|
|
137
|
+
super(ArrayCacheBySymbolById, self).__init__(max_size)
|
|
138
|
+
self._nested_new_updates_by_symbol = True
|
|
139
|
+
self.hashmap = {}
|
|
140
|
+
self._index = collections.deque([], max_size)
|
|
141
|
+
|
|
142
|
+
def append(self, item):
|
|
143
|
+
by_id = self.hashmap.setdefault(item['symbol'], {})
|
|
144
|
+
if item['id'] in by_id:
|
|
145
|
+
reference = by_id[item['id']]
|
|
146
|
+
if reference != item:
|
|
147
|
+
reference.update(item)
|
|
148
|
+
item = reference
|
|
149
|
+
index = self._index.index(item['id'])
|
|
150
|
+
del self._deque[index]
|
|
151
|
+
del self._index[index]
|
|
152
|
+
else:
|
|
153
|
+
by_id[item['id']] = item
|
|
154
|
+
if len(self._deque) == self._deque.maxlen:
|
|
155
|
+
delete_item = self._deque.popleft()
|
|
156
|
+
self._index.popleft()
|
|
157
|
+
try:
|
|
158
|
+
del self.hashmap[delete_item['symbol']][delete_item['id']]
|
|
159
|
+
except Exception as e:
|
|
160
|
+
logger.error(f"Error deleting item from hashmap: {delete_item}. Error:{e}")
|
|
161
|
+
self._deque.append(item)
|
|
162
|
+
self._index.append(item['id'])
|
|
163
|
+
if self._clear_all_updates:
|
|
164
|
+
self._clear_all_updates = False
|
|
165
|
+
self._clear_updates_by_symbol.clear()
|
|
166
|
+
self._all_new_updates = 0
|
|
167
|
+
self._new_updates_by_symbol.clear()
|
|
168
|
+
if item['symbol'] not in self._new_updates_by_symbol:
|
|
169
|
+
self._new_updates_by_symbol[item['symbol']] = set()
|
|
170
|
+
if self._clear_updates_by_symbol.get(item['symbol']):
|
|
171
|
+
self._clear_updates_by_symbol[item['symbol']] = False
|
|
172
|
+
self._new_updates_by_symbol[item['symbol']].clear()
|
|
173
|
+
id_set = self._new_updates_by_symbol[item['symbol']]
|
|
174
|
+
before_length = len(id_set)
|
|
175
|
+
id_set.add(item['id'])
|
|
176
|
+
after_length = len(id_set)
|
|
177
|
+
self._all_new_updates = (self._all_new_updates or 0) + (after_length - before_length)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
class ArrayCacheBySymbolBySide(ArrayCache):
|
|
181
|
+
def __init__(self, max_size=None):
|
|
182
|
+
super(ArrayCacheBySymbolBySide, self).__init__(max_size)
|
|
183
|
+
self._nested_new_updates_by_symbol = True
|
|
184
|
+
self.hashmap = {}
|
|
185
|
+
self._index = collections.deque([], max_size)
|
|
186
|
+
|
|
187
|
+
def append(self, item):
|
|
188
|
+
by_side = self.hashmap.setdefault(item['symbol'], {})
|
|
189
|
+
if item['side'] in by_side:
|
|
190
|
+
reference = by_side[item['side']]
|
|
191
|
+
if reference != item:
|
|
192
|
+
reference.update(item)
|
|
193
|
+
item = reference
|
|
194
|
+
index = self._index.index(item['symbol'] + item['side'])
|
|
195
|
+
del self._deque[index]
|
|
196
|
+
del self._index[index]
|
|
197
|
+
else:
|
|
198
|
+
by_side[item['side']] = item
|
|
199
|
+
if len(self._deque) == self._deque.maxlen:
|
|
200
|
+
delete_item = self._deque.popleft()
|
|
201
|
+
self._index.popleft()
|
|
202
|
+
del self.hashmap[delete_item['symbol']][delete_item['side']]
|
|
203
|
+
self._deque.append(item)
|
|
204
|
+
self._index.append(item['symbol'] + item['side'])
|
|
205
|
+
if self._clear_all_updates:
|
|
206
|
+
self._clear_all_updates = False
|
|
207
|
+
self._clear_updates_by_symbol.clear()
|
|
208
|
+
self._all_new_updates = 0
|
|
209
|
+
self._new_updates_by_symbol.clear()
|
|
210
|
+
if item['symbol'] not in self._new_updates_by_symbol:
|
|
211
|
+
self._new_updates_by_symbol[item['symbol']] = set()
|
|
212
|
+
if self._clear_updates_by_symbol.get(item['symbol']):
|
|
213
|
+
self._clear_updates_by_symbol[item['symbol']] = False
|
|
214
|
+
self._new_updates_by_symbol[item['symbol']].clear()
|
|
215
|
+
side_set = self._new_updates_by_symbol[item['symbol']]
|
|
216
|
+
before_length = len(side_set)
|
|
217
|
+
side_set.add(item['side'])
|
|
218
|
+
after_length = len(side_set)
|
|
219
|
+
self._all_new_updates = (self._all_new_updates or 0) + (after_length - before_length)
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
orjson = None
|
|
4
|
+
try:
|
|
5
|
+
import orjson as orjson
|
|
6
|
+
except ImportError:
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
|
|
11
|
+
from asyncio import sleep, ensure_future, wait_for, TimeoutError, BaseEventLoop, Future as asyncioFuture
|
|
12
|
+
from .functions import milliseconds, iso8601, deep_extend, is_json_encoded_object
|
|
13
|
+
from ccxt import NetworkError, RequestTimeout
|
|
14
|
+
from ccxt.async_support.base.ws.future import Future
|
|
15
|
+
from ccxt.async_support.base.ws.functions import gunzip, inflate
|
|
16
|
+
from typing import Dict
|
|
17
|
+
|
|
18
|
+
from aiohttp import WSMsgType
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Client(object):
|
|
22
|
+
|
|
23
|
+
url = None
|
|
24
|
+
ws = None
|
|
25
|
+
futures: Dict[str, Future] = {}
|
|
26
|
+
options = {} # ws-specific options
|
|
27
|
+
subscriptions = {}
|
|
28
|
+
rejections = {}
|
|
29
|
+
on_message_callback = None
|
|
30
|
+
on_error_callback = None
|
|
31
|
+
on_close_callback = None
|
|
32
|
+
on_connected_callback = None
|
|
33
|
+
connectionStarted = None
|
|
34
|
+
connectionEstablished = None
|
|
35
|
+
isConnected = False
|
|
36
|
+
connectionTimeout = 10000 # ms, false to disable
|
|
37
|
+
connection = None
|
|
38
|
+
error = None # low-level networking exception, if any
|
|
39
|
+
connected = None # connection-related Future
|
|
40
|
+
keepAlive = 5000
|
|
41
|
+
heartbeat = True
|
|
42
|
+
maxPingPongMisses = 2.0 # how many missed pongs to raise a timeout
|
|
43
|
+
lastPong = None
|
|
44
|
+
ping = None # ping-function if defined
|
|
45
|
+
proxy = None
|
|
46
|
+
verbose = False # verbose output
|
|
47
|
+
gunzip = False
|
|
48
|
+
inflate = False
|
|
49
|
+
throttle = None
|
|
50
|
+
connecting = False
|
|
51
|
+
asyncio_loop: BaseEventLoop = None
|
|
52
|
+
ping_looper = None
|
|
53
|
+
decompressBinary = True # decompress binary messages by default
|
|
54
|
+
|
|
55
|
+
def __init__(self, url, on_message_callback, on_error_callback, on_close_callback, on_connected_callback, config={}):
|
|
56
|
+
defaults = {
|
|
57
|
+
'url': url,
|
|
58
|
+
'futures': {},
|
|
59
|
+
'subscriptions': {},
|
|
60
|
+
'rejections': {},
|
|
61
|
+
'on_message_callback': on_message_callback,
|
|
62
|
+
'on_error_callback': on_error_callback,
|
|
63
|
+
'on_close_callback': on_close_callback,
|
|
64
|
+
'on_connected_callback': on_connected_callback,
|
|
65
|
+
}
|
|
66
|
+
settings = {}
|
|
67
|
+
settings.update(defaults)
|
|
68
|
+
settings.update(config)
|
|
69
|
+
for key in settings:
|
|
70
|
+
if hasattr(self, key) and isinstance(getattr(self, key), dict):
|
|
71
|
+
setattr(self, key, deep_extend(getattr(self, key), settings[key]))
|
|
72
|
+
else:
|
|
73
|
+
setattr(self, key, settings[key])
|
|
74
|
+
# connection-related Future
|
|
75
|
+
self.options = config
|
|
76
|
+
self.connected = Future()
|
|
77
|
+
|
|
78
|
+
def future(self, message_hash):
|
|
79
|
+
if message_hash not in self.futures or self.futures[message_hash].cancelled():
|
|
80
|
+
self.futures[message_hash] = Future()
|
|
81
|
+
future = self.futures[message_hash]
|
|
82
|
+
if message_hash in self.rejections:
|
|
83
|
+
future.reject(self.rejections[message_hash])
|
|
84
|
+
del self.rejections[message_hash]
|
|
85
|
+
return future
|
|
86
|
+
|
|
87
|
+
def reusable_future(self, message_hash):
|
|
88
|
+
return self.future(message_hash) # only used in go
|
|
89
|
+
|
|
90
|
+
def reusableFuture(self, message_hash):
|
|
91
|
+
return self.future(message_hash) # only used in go
|
|
92
|
+
|
|
93
|
+
def resolve(self, result, message_hash):
|
|
94
|
+
if self.verbose and message_hash is None:
|
|
95
|
+
self.log(iso8601(milliseconds()), 'resolve received None messageHash')
|
|
96
|
+
if message_hash in self.futures:
|
|
97
|
+
future = self.futures[message_hash]
|
|
98
|
+
future.resolve(result)
|
|
99
|
+
del self.futures[message_hash]
|
|
100
|
+
return result
|
|
101
|
+
|
|
102
|
+
def reject(self, result, message_hash=None):
|
|
103
|
+
if message_hash is not None:
|
|
104
|
+
if message_hash in self.futures:
|
|
105
|
+
future = self.futures[message_hash]
|
|
106
|
+
future.reject(result)
|
|
107
|
+
del self.futures[message_hash]
|
|
108
|
+
else:
|
|
109
|
+
self.rejections[message_hash] = result
|
|
110
|
+
else:
|
|
111
|
+
message_hashes = list(self.futures.keys())
|
|
112
|
+
for message_hash in message_hashes:
|
|
113
|
+
self.reject(result, message_hash)
|
|
114
|
+
return result
|
|
115
|
+
|
|
116
|
+
def receive_loop(self):
|
|
117
|
+
if self.verbose:
|
|
118
|
+
self.log(iso8601(milliseconds()), 'receive loop')
|
|
119
|
+
if not self.closed():
|
|
120
|
+
# let's drain the aiohttp buffer to avoid latency
|
|
121
|
+
if self.buffer and len(self.buffer) > 1:
|
|
122
|
+
size_delta = 0
|
|
123
|
+
while len(self.buffer) > 1:
|
|
124
|
+
message, size = self.buffer.popleft()
|
|
125
|
+
size_delta += size
|
|
126
|
+
self.handle_message(message)
|
|
127
|
+
# we must update the size of the last message inside WebSocketDataQueue
|
|
128
|
+
# self.receive() calls WebSocketDataQueue.read() that calls WebSocketDataQueue._read_from_buffer()
|
|
129
|
+
# which updates the size of the buffer, the _size will overflow and pause the transport
|
|
130
|
+
# make sure to set the enviroment variable AIOHTTP_NO_EXTENSIONS=Y to check
|
|
131
|
+
# print(self.connection._conn.protocol._payload._size)
|
|
132
|
+
self.buffer[0] = (self.buffer[0][0], self.buffer[0][1] + size_delta)
|
|
133
|
+
|
|
134
|
+
task = self.asyncio_loop.create_task(self.receive())
|
|
135
|
+
|
|
136
|
+
def after_interrupt(resolved: asyncioFuture):
|
|
137
|
+
exception = resolved.exception()
|
|
138
|
+
if exception is None:
|
|
139
|
+
self.handle_message(resolved.result())
|
|
140
|
+
self.asyncio_loop.call_soon(self.receive_loop)
|
|
141
|
+
else:
|
|
142
|
+
error = NetworkError(str(exception))
|
|
143
|
+
if self.verbose:
|
|
144
|
+
self.log(iso8601(milliseconds()), 'receive_loop', 'Exception', error)
|
|
145
|
+
self.reject(error)
|
|
146
|
+
|
|
147
|
+
task.add_done_callback(after_interrupt)
|
|
148
|
+
else:
|
|
149
|
+
# connection got terminated after the connection was made and before the receive loop ran
|
|
150
|
+
self.on_close(1006)
|
|
151
|
+
|
|
152
|
+
async def open(self, session, backoff_delay=0):
|
|
153
|
+
# exponential backoff for consequent connections if necessary
|
|
154
|
+
if backoff_delay:
|
|
155
|
+
await sleep(backoff_delay)
|
|
156
|
+
if self.verbose:
|
|
157
|
+
self.log(iso8601(milliseconds()), 'connecting to', self.url, 'with timeout', self.connectionTimeout, 'ms')
|
|
158
|
+
self.connectionStarted = milliseconds()
|
|
159
|
+
try:
|
|
160
|
+
coroutine = self.create_connection(session)
|
|
161
|
+
self.connection = await wait_for(coroutine, timeout=int(self.connectionTimeout / 1000))
|
|
162
|
+
self.connecting = False
|
|
163
|
+
self.connectionEstablished = milliseconds()
|
|
164
|
+
self.isConnected = True
|
|
165
|
+
if self.verbose:
|
|
166
|
+
self.log(iso8601(milliseconds()), 'connected')
|
|
167
|
+
self.connected.resolve(self.url)
|
|
168
|
+
self.on_connected_callback(self)
|
|
169
|
+
# run both loops forever
|
|
170
|
+
self.ping_looper = ensure_future(self.ping_loop(), loop=self.asyncio_loop)
|
|
171
|
+
self.asyncio_loop.call_soon(self.receive_loop)
|
|
172
|
+
except TimeoutError:
|
|
173
|
+
# connection timeout
|
|
174
|
+
error = RequestTimeout('Connection timeout')
|
|
175
|
+
if self.verbose:
|
|
176
|
+
self.log(iso8601(milliseconds()), 'RequestTimeout', error)
|
|
177
|
+
self.on_error(error)
|
|
178
|
+
except Exception as e:
|
|
179
|
+
# connection failed or rejected (ConnectionRefusedError, ClientConnectorError)
|
|
180
|
+
error = NetworkError(e)
|
|
181
|
+
if self.verbose:
|
|
182
|
+
self.log(iso8601(milliseconds()), 'NetworkError', error)
|
|
183
|
+
self.on_error(error)
|
|
184
|
+
|
|
185
|
+
@property
|
|
186
|
+
def buffer(self):
|
|
187
|
+
# looks like they exposed it in C
|
|
188
|
+
# this means we can bypass it
|
|
189
|
+
# https://github.com/aio-libs/aiohttp/blob/master/aiohttp/_websocket/reader_c.pxd#L53C24-L53C31
|
|
190
|
+
# these checks are necessary to protect these errors: AttributeError: 'NoneType' object has no attribute '_buffer'
|
|
191
|
+
# upon getting an error message
|
|
192
|
+
if self.connection is None:
|
|
193
|
+
return None
|
|
194
|
+
if self.connection._conn is None:
|
|
195
|
+
return None
|
|
196
|
+
if self.connection._conn.protocol is None:
|
|
197
|
+
return None
|
|
198
|
+
if self.connection._conn.protocol._payload is None:
|
|
199
|
+
return None
|
|
200
|
+
return self.connection._conn.protocol._payload._buffer
|
|
201
|
+
|
|
202
|
+
def connect(self, session, backoff_delay=0):
|
|
203
|
+
if not self.connection and not self.connecting:
|
|
204
|
+
self.connecting = True
|
|
205
|
+
ensure_future(self.open(session, backoff_delay), loop=self.asyncio_loop)
|
|
206
|
+
return self.connected
|
|
207
|
+
|
|
208
|
+
def on_error(self, error):
|
|
209
|
+
if self.verbose:
|
|
210
|
+
self.log(iso8601(milliseconds()), 'on_error', error)
|
|
211
|
+
self.error = error
|
|
212
|
+
self.reject(error)
|
|
213
|
+
self.on_error_callback(self, error)
|
|
214
|
+
if not self.closed():
|
|
215
|
+
ensure_future(self.close(1006), loop=self.asyncio_loop)
|
|
216
|
+
|
|
217
|
+
def on_close(self, code):
|
|
218
|
+
if self.verbose:
|
|
219
|
+
self.log(iso8601(milliseconds()), 'on_close', code)
|
|
220
|
+
if not self.error:
|
|
221
|
+
self.reject(NetworkError('Connection closed by remote server, closing code ' + str(code)))
|
|
222
|
+
self.on_close_callback(self, code)
|
|
223
|
+
ensure_future(self.aiohttp_close(), loop=self.asyncio_loop)
|
|
224
|
+
|
|
225
|
+
def log(self, *args):
|
|
226
|
+
print(*args)
|
|
227
|
+
|
|
228
|
+
def closed(self):
|
|
229
|
+
return (self.connection is None) or self.connection.closed
|
|
230
|
+
|
|
231
|
+
def receive(self):
|
|
232
|
+
return self.connection.receive()
|
|
233
|
+
|
|
234
|
+
# helper method for binary and text messages
|
|
235
|
+
def handle_text_or_binary_message(self, data):
|
|
236
|
+
if self.verbose:
|
|
237
|
+
self.log(iso8601(milliseconds()), 'message', data)
|
|
238
|
+
if self.decompressBinary and isinstance(data, bytes):
|
|
239
|
+
data = data.decode()
|
|
240
|
+
# decoded = json.loads(data) if is_json_encoded_object(data) else data
|
|
241
|
+
decode = None
|
|
242
|
+
if is_json_encoded_object(data):
|
|
243
|
+
if orjson is None:
|
|
244
|
+
decode = json.loads(data)
|
|
245
|
+
else:
|
|
246
|
+
decode = orjson.loads(data)
|
|
247
|
+
else:
|
|
248
|
+
decode = data
|
|
249
|
+
self.on_message_callback(self, decode)
|
|
250
|
+
|
|
251
|
+
def handle_message(self, message):
|
|
252
|
+
# self.log(iso8601(milliseconds()), message)
|
|
253
|
+
if message.type == WSMsgType.TEXT:
|
|
254
|
+
self.handle_text_or_binary_message(message.data)
|
|
255
|
+
elif message.type == WSMsgType.BINARY:
|
|
256
|
+
data = message.data
|
|
257
|
+
if self.gunzip:
|
|
258
|
+
data = gunzip(data)
|
|
259
|
+
elif self.inflate:
|
|
260
|
+
data = inflate(data)
|
|
261
|
+
self.handle_text_or_binary_message(data)
|
|
262
|
+
# autoping is responsible for automatically replying with pong
|
|
263
|
+
# to a ping incoming from a server, we have to disable autoping
|
|
264
|
+
# with aiohttp's websockets and respond with pong manually
|
|
265
|
+
# otherwise aiohttp's websockets client won't trigger WSMsgType.PONG
|
|
266
|
+
elif message.type == WSMsgType.PING:
|
|
267
|
+
if self.verbose:
|
|
268
|
+
self.log(iso8601(milliseconds()), 'ping', message)
|
|
269
|
+
ensure_future(self.connection.pong(message.data), loop=self.asyncio_loop)
|
|
270
|
+
elif message.type == WSMsgType.PONG:
|
|
271
|
+
self.lastPong = milliseconds()
|
|
272
|
+
if self.verbose:
|
|
273
|
+
self.log(iso8601(milliseconds()), 'pong', message)
|
|
274
|
+
pass
|
|
275
|
+
elif message.type == WSMsgType.CLOSE:
|
|
276
|
+
if self.verbose:
|
|
277
|
+
self.log(iso8601(milliseconds()), 'close', self.closed(), message)
|
|
278
|
+
self.on_close(message.data)
|
|
279
|
+
elif message.type == WSMsgType.ERROR:
|
|
280
|
+
if self.verbose:
|
|
281
|
+
self.log(iso8601(milliseconds()), 'error', message)
|
|
282
|
+
error = NetworkError(str(message))
|
|
283
|
+
self.on_error(error)
|
|
284
|
+
|
|
285
|
+
def create_connection(self, session):
|
|
286
|
+
# autoping is responsible for automatically replying with pong
|
|
287
|
+
# to a ping incoming from a server, we have to disable autoping
|
|
288
|
+
# with aiohttp's websockets and respond with pong manually
|
|
289
|
+
# otherwise aiohttp's websockets client won't trigger WSMsgType.PONG
|
|
290
|
+
# call aenter here to simulate async with otherwise we get the error "await not called with future"
|
|
291
|
+
# if connecting to a non-existent endpoint
|
|
292
|
+
# set cookies if defined
|
|
293
|
+
if 'cookies' in self.options:
|
|
294
|
+
for key, value in self.options['cookies'].items():
|
|
295
|
+
session.cookie_jar.update_cookies({key: value})
|
|
296
|
+
if (self.proxy):
|
|
297
|
+
return session.ws_connect(self.url, autoping=False, autoclose=False, headers=self.options.get('headers'), proxy=self.proxy, max_msg_size=10485760).__aenter__()
|
|
298
|
+
return session.ws_connect(self.url, autoping=False, autoclose=False, headers=self.options.get('headers'), max_msg_size=10485760).__aenter__()
|
|
299
|
+
|
|
300
|
+
async def send(self, message):
|
|
301
|
+
if self.verbose:
|
|
302
|
+
self.log(iso8601(milliseconds()), 'sending', message)
|
|
303
|
+
send_msg = None
|
|
304
|
+
if isinstance(message, str):
|
|
305
|
+
send_msg = message
|
|
306
|
+
else:
|
|
307
|
+
if orjson is None:
|
|
308
|
+
send_msg = json.dumps(message, separators=(',', ':'))
|
|
309
|
+
else:
|
|
310
|
+
send_msg = orjson.dumps(message).decode('utf-8')
|
|
311
|
+
if self.closed():
|
|
312
|
+
raise ConnectionError('Cannot Send Message: Connection closed before send')
|
|
313
|
+
return await self.connection.send_str(send_msg)
|
|
314
|
+
|
|
315
|
+
async def close(self, code=1000):
|
|
316
|
+
if self.verbose:
|
|
317
|
+
self.log(iso8601(milliseconds()), 'closing', code)
|
|
318
|
+
for future in self.futures.values():
|
|
319
|
+
future.cancel()
|
|
320
|
+
await self.aiohttp_close()
|
|
321
|
+
|
|
322
|
+
async def aiohttp_close(self):
|
|
323
|
+
if not self.closed():
|
|
324
|
+
await self.connection.close()
|
|
325
|
+
# these will end automatically once self.closed() = True
|
|
326
|
+
# so we don't need to cancel them
|
|
327
|
+
if self.ping_looper:
|
|
328
|
+
self.ping_looper.cancel()
|
|
329
|
+
|
|
330
|
+
async def ping_loop(self):
|
|
331
|
+
if self.verbose:
|
|
332
|
+
self.log(iso8601(milliseconds()), 'ping loop')
|
|
333
|
+
while self.keepAlive and not self.closed():
|
|
334
|
+
now = milliseconds()
|
|
335
|
+
self.lastPong = now if self.lastPong is None else self.lastPong
|
|
336
|
+
if (self.lastPong + self.keepAlive * self.maxPingPongMisses) < now:
|
|
337
|
+
self.on_error(RequestTimeout('Connection to ' + self.url + ' timed out due to a ping-pong keepalive missing on time'))
|
|
338
|
+
# the following ping-clause is not necessary with aiohttp's built-in ws
|
|
339
|
+
# since it has a heartbeat option (see create_connection above)
|
|
340
|
+
# however some exchanges require a text-type ping message
|
|
341
|
+
# therefore we need this clause anyway
|
|
342
|
+
else:
|
|
343
|
+
if self.ping:
|
|
344
|
+
try:
|
|
345
|
+
await self.send(self.ping(self))
|
|
346
|
+
except Exception as e:
|
|
347
|
+
self.on_error(e)
|
|
348
|
+
else:
|
|
349
|
+
await self.connection.ping()
|
|
350
|
+
await sleep(self.keepAlive / 1000)
|