coinex-api 0.0.89__py3-none-any.whl → 0.0.110__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 coinex-api might be problematic. Click here for more details.
- coinex/ccxt/__init__.py +1 -1
- coinex/ccxt/async_support/__init__.py +1 -1
- coinex/ccxt/async_support/base/exchange.py +139 -10
- coinex/ccxt/async_support/base/throttler.py +1 -1
- coinex/ccxt/async_support/base/ws/cache.py +1 -0
- coinex/ccxt/async_support/base/ws/client.py +26 -4
- coinex/ccxt/async_support/coinex.py +2 -2
- coinex/ccxt/base/exchange.py +587 -91
- coinex/ccxt/base/types.py +11 -2
- coinex/ccxt/coinex.py +2 -2
- coinex/ccxt/pro/__init__.py +1 -1
- coinex/ccxt/pro/coinex.py +10 -7
- coinex/ccxt/static_dependencies/bip/__init__.py +6 -0
- coinex/ccxt/static_dependencies/bip/addr/P2PKH_addr.py +205 -0
- coinex/ccxt/static_dependencies/bip/addr/__init__.py +5 -0
- coinex/ccxt/static_dependencies/bip/addr/addr_dec_utils.py +125 -0
- coinex/ccxt/static_dependencies/bip/addr/addr_key_validator.py +162 -0
- coinex/ccxt/static_dependencies/bip/addr/iaddr_decoder.py +48 -0
- coinex/ccxt/static_dependencies/bip/addr/iaddr_encoder.py +50 -0
- coinex/ccxt/static_dependencies/bip/base58/__init__.py +3 -0
- coinex/ccxt/static_dependencies/bip/base58/base58.py +207 -0
- coinex/ccxt/static_dependencies/bip/base58/base58_ex.py +25 -0
- coinex/ccxt/static_dependencies/bip/base58/base58_xmr.py +155 -0
- coinex/ccxt/static_dependencies/bip/bech32/__init__.py +4 -0
- coinex/ccxt/static_dependencies/bip/bech32/bch_bech32.py +220 -0
- coinex/ccxt/static_dependencies/bip/bech32/bech32.py +235 -0
- coinex/ccxt/static_dependencies/bip/bech32/bech32_base.py +246 -0
- coinex/ccxt/static_dependencies/bip/bech32/bech32_ex.py +25 -0
- coinex/ccxt/static_dependencies/bip/bech32/segwit_bech32.py +173 -0
- coinex/ccxt/static_dependencies/bip/bip32/__init__.py +14 -0
- coinex/ccxt/static_dependencies/bip/bip32/base/__init__.py +3 -0
- coinex/ccxt/static_dependencies/bip/bip32/base/bip32_base.py +581 -0
- coinex/ccxt/static_dependencies/bip/bip32/base/ibip32_key_derivator.py +83 -0
- coinex/ccxt/static_dependencies/bip/bip32/base/ibip32_mst_key_generator.py +47 -0
- coinex/ccxt/static_dependencies/bip/bip32/bip32_const.py +35 -0
- coinex/ccxt/static_dependencies/bip/bip32/bip32_ex.py +29 -0
- coinex/ccxt/static_dependencies/bip/bip32/bip32_key_data.py +500 -0
- coinex/ccxt/static_dependencies/bip/bip32/bip32_key_net_ver.py +83 -0
- coinex/ccxt/static_dependencies/bip/bip32/bip32_key_ser.py +294 -0
- coinex/ccxt/static_dependencies/bip/bip32/bip32_keys.py +457 -0
- coinex/ccxt/static_dependencies/bip/bip32/bip32_path.py +247 -0
- coinex/ccxt/static_dependencies/bip/bip32/bip32_utils.py +72 -0
- coinex/ccxt/static_dependencies/bip/bip32/kholaw/__init__.py +4 -0
- coinex/ccxt/static_dependencies/bip/bip32/kholaw/bip32_kholaw_ed25519.py +82 -0
- coinex/ccxt/static_dependencies/bip/bip32/kholaw/bip32_kholaw_ed25519_key_derivator.py +118 -0
- coinex/ccxt/static_dependencies/bip/bip32/kholaw/bip32_kholaw_key_derivator_base.py +204 -0
- coinex/ccxt/static_dependencies/bip/bip32/kholaw/bip32_kholaw_mst_key_generator.py +119 -0
- coinex/ccxt/static_dependencies/bip/bip32/slip10/__init__.py +1 -0
- coinex/ccxt/static_dependencies/bip/bip32/slip10/bip32_slip10_key_derivator.py +200 -0
- coinex/ccxt/static_dependencies/bip/bip32/slip10/bip32_slip10_mst_key_generator.py +168 -0
- coinex/ccxt/static_dependencies/bip/bip32/slip10/bip32_slip10_secp256k1.py +82 -0
- coinex/ccxt/static_dependencies/bip/bip44/__init__.py +1 -0
- coinex/ccxt/static_dependencies/bip/bip44/bip44.py +265 -0
- coinex/ccxt/static_dependencies/bip/bip44_base/__init__.py +3 -0
- coinex/ccxt/static_dependencies/bip/bip44_base/bip44_base.py +624 -0
- coinex/ccxt/static_dependencies/bip/bip44_base/bip44_base_ex.py +25 -0
- coinex/ccxt/static_dependencies/bip/bip44_base/bip44_keys.py +225 -0
- coinex/ccxt/static_dependencies/bip/coin_conf/__init__.py +2 -0
- coinex/ccxt/static_dependencies/bip/coin_conf/coin_conf.py +68 -0
- coinex/ccxt/static_dependencies/bip/coin_conf/coins_conf.py +890 -0
- coinex/ccxt/static_dependencies/bip/conf/__init__.py +0 -0
- coinex/ccxt/static_dependencies/bip/conf/bip44/__init__.py +3 -0
- coinex/ccxt/static_dependencies/bip/conf/bip44/bip44_coins.py +126 -0
- coinex/ccxt/static_dependencies/bip/conf/bip44/bip44_conf.py +1360 -0
- coinex/ccxt/static_dependencies/bip/conf/bip44/bip44_conf_getter.py +153 -0
- coinex/ccxt/static_dependencies/bip/conf/bip49/__init__.py +3 -0
- coinex/ccxt/static_dependencies/bip/conf/bip49/bip49_coins.py +53 -0
- coinex/ccxt/static_dependencies/bip/conf/bip49/bip49_conf.py +366 -0
- coinex/ccxt/static_dependencies/bip/conf/bip49/bip49_conf_getter.py +80 -0
- coinex/ccxt/static_dependencies/bip/conf/bip84/__init__.py +3 -0
- coinex/ccxt/static_dependencies/bip/conf/bip84/bip84_coins.py +39 -0
- coinex/ccxt/static_dependencies/bip/conf/bip84/bip84_conf.py +113 -0
- coinex/ccxt/static_dependencies/bip/conf/bip84/bip84_conf_getter.py +66 -0
- coinex/ccxt/static_dependencies/bip/conf/bip86/__init__.py +3 -0
- coinex/ccxt/static_dependencies/bip/conf/bip86/bip86_coins.py +37 -0
- coinex/ccxt/static_dependencies/bip/conf/bip86/bip86_conf.py +83 -0
- coinex/ccxt/static_dependencies/bip/conf/bip86/bip86_conf_getter.py +64 -0
- coinex/ccxt/static_dependencies/bip/conf/common/__init__.py +8 -0
- coinex/ccxt/static_dependencies/bip/conf/common/atom_addr.py +104 -0
- coinex/ccxt/static_dependencies/bip/conf/common/bip_bitcoin_cash_conf.py +106 -0
- coinex/ccxt/static_dependencies/bip/conf/common/bip_coin_conf.py +217 -0
- coinex/ccxt/static_dependencies/bip/conf/common/bip_coins.py +28 -0
- coinex/ccxt/static_dependencies/bip/conf/common/bip_conf_const.py +30 -0
- coinex/ccxt/static_dependencies/bip/conf/common/bip_litecoin_conf.py +121 -0
- coinex/ccxt/static_dependencies/bip/ecc/__init__.py +42 -0
- coinex/ccxt/static_dependencies/bip/ecc/common/__init__.py +0 -0
- coinex/ccxt/static_dependencies/bip/ecc/common/dummy_point.py +219 -0
- coinex/ccxt/static_dependencies/bip/ecc/common/ikeys.py +263 -0
- coinex/ccxt/static_dependencies/bip/ecc/common/ipoint.py +190 -0
- coinex/ccxt/static_dependencies/bip/ecc/conf.py +28 -0
- coinex/ccxt/static_dependencies/bip/ecc/curve/__init__.py +0 -0
- coinex/ccxt/static_dependencies/bip/ecc/curve/elliptic_curve.py +121 -0
- coinex/ccxt/static_dependencies/bip/ecc/curve/elliptic_curve_getter.py +74 -0
- coinex/ccxt/static_dependencies/bip/ecc/curve/elliptic_curve_types.py +37 -0
- coinex/ccxt/static_dependencies/bip/ecc/ecdsa/__init__.py +0 -0
- coinex/ccxt/static_dependencies/bip/ecc/ecdsa/ecdsa_keys.py +36 -0
- coinex/ccxt/static_dependencies/bip/ecc/secp256k1/__init__.py +0 -0
- coinex/ccxt/static_dependencies/bip/ecc/secp256k1/secp256k1.py +36 -0
- coinex/ccxt/static_dependencies/bip/ecc/secp256k1/secp256k1_const.py +59 -0
- coinex/ccxt/static_dependencies/bip/ecc/secp256k1/secp256k1_keys_ecdsa.py +248 -0
- coinex/ccxt/static_dependencies/bip/ecc/secp256k1/secp256k1_point_ecdsa.py +234 -0
- coinex/ccxt/static_dependencies/bip/slip/__init__.py +0 -0
- coinex/ccxt/static_dependencies/bip/slip/slip173/__init__.py +1 -0
- coinex/ccxt/static_dependencies/bip/slip/slip173/slip173.py +60 -0
- coinex/ccxt/static_dependencies/bip/slip/slip32/__init__.py +4 -0
- coinex/ccxt/static_dependencies/bip/slip/slip32/slip32.py +322 -0
- coinex/ccxt/static_dependencies/bip/slip/slip32/slip32_key_net_ver.py +62 -0
- coinex/ccxt/static_dependencies/bip/slip/slip44/__init__.py +1 -0
- coinex/ccxt/static_dependencies/bip/slip/slip44/slip44.py +81 -0
- coinex/ccxt/static_dependencies/bip/utils/__init__.py +0 -0
- coinex/ccxt/static_dependencies/bip/utils/conf/__init__.py +1 -0
- coinex/ccxt/static_dependencies/bip/utils/conf/coin_names.py +59 -0
- coinex/ccxt/static_dependencies/bip/utils/crypto/__init__.py +10 -0
- coinex/ccxt/static_dependencies/bip/utils/crypto/aes_ecb.py +152 -0
- coinex/ccxt/static_dependencies/bip/utils/crypto/blake2.py +191 -0
- coinex/ccxt/static_dependencies/bip/utils/crypto/chacha20_poly1305.py +101 -0
- coinex/ccxt/static_dependencies/bip/utils/crypto/hash160.py +57 -0
- coinex/ccxt/static_dependencies/bip/utils/crypto/hmac.py +118 -0
- coinex/ccxt/static_dependencies/bip/utils/crypto/pbkdf2.py +66 -0
- coinex/ccxt/static_dependencies/bip/utils/crypto/ripemd.py +58 -0
- coinex/ccxt/static_dependencies/bip/utils/crypto/scrypt.py +66 -0
- coinex/ccxt/static_dependencies/bip/utils/crypto/sha2.py +182 -0
- coinex/ccxt/static_dependencies/bip/utils/crypto/sha3.py +99 -0
- coinex/ccxt/static_dependencies/bip/utils/misc/__init__.py +7 -0
- coinex/ccxt/static_dependencies/bip/utils/misc/algo.py +108 -0
- coinex/ccxt/static_dependencies/bip/utils/misc/base32.py +151 -0
- coinex/ccxt/static_dependencies/bip/utils/misc/bit.py +115 -0
- coinex/ccxt/static_dependencies/bip/utils/misc/bytes.py +200 -0
- coinex/ccxt/static_dependencies/bip/utils/misc/data_bytes.py +181 -0
- coinex/ccxt/static_dependencies/bip/utils/misc/integer.py +97 -0
- coinex/ccxt/static_dependencies/bip/utils/misc/string.py +54 -0
- coinex/ccxt/static_dependencies/bip/utils/typing/__init__.py +1 -0
- coinex/ccxt/static_dependencies/bip/utils/typing/literal.py +27 -0
- coinex/ccxt/static_dependencies/bip/wif/__init__.py +1 -0
- coinex/ccxt/static_dependencies/bip/wif/wif.py +144 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/amino/amino_pb2.py +31 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/cosmos/base/v1beta1/coin_pb2.py +47 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/cosmos/crypto/multisig/keys_pb2.py +33 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/cosmos/crypto/multisig/v1beta1/multisig_pb2.py +33 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/cosmos/crypto/secp256k1/keys_pb2.py +34 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/cosmos/msg/v1/msg_pb2.py +27 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/cosmos/tx/signing/v1beta1/signing_pb2.py +38 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/cosmos/tx/v1beta1/tx_pb2.py +75 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/cosmos_proto/cosmos_pb2.py +36 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/accountplus/accountplus_pb2.py +31 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/accountplus/genesis_pb2.py +40 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/accountplus/models_pb2.py +26 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/accountplus/params_pb2.py +29 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/accountplus/query_pb2.py +57 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/accountplus/tx_pb2.py +51 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/block_rate_limit_config_pb2.py +37 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/clob_pair_pb2.py +41 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/equity_tier_limit_config_pb2.py +35 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/finalize_block_pb2.py +27 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/liquidations_config_pb2.py +39 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/liquidations_pb2.py +38 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/matches_pb2.py +55 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/mev_pb2.py +49 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/operation_pb2.py +32 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/order_pb2.py +86 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/order_removals_pb2.py +32 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/process_proposer_matches_events_pb2.py +42 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/query_pb2.py +124 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/streaming_pb2.py +29 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/tx_pb2.py +117 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/sending/genesis_pb2.py +26 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/sending/query_pb2.py +26 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/sending/transfer_pb2.py +61 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/sending/tx_pb2.py +37 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/subaccounts/asset_position_pb2.py +29 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/subaccounts/genesis_pb2.py +30 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/subaccounts/perpetual_position_pb2.py +33 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/subaccounts/query_pb2.py +63 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/subaccounts/streaming_pb2.py +31 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/subaccounts/subaccount_pb2.py +33 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/gogoproto/gogo_pb2.py +102 -0
- coinex/ccxt/static_dependencies/dydx_v4_client/registry.py +38 -0
- coinex/ccxt/static_dependencies/ecdsa/ellipticcurve.py +842 -0
- coinex/ccxt/static_dependencies/ecdsa/keys.py +15 -4
- coinex/ccxt/static_dependencies/mnemonic/__init__.py +4 -0
- coinex/ccxt/static_dependencies/mnemonic/mnemonic.py +282 -0
- coinex/ccxt/static_dependencies/mnemonic/py.typed +1 -0
- coinex/ccxt/static_dependencies/mnemonic/wordlist/chinese_simplified.txt +2048 -0
- coinex/ccxt/static_dependencies/mnemonic/wordlist/chinese_traditional.txt +2048 -0
- coinex/ccxt/static_dependencies/mnemonic/wordlist/czech.txt +2048 -0
- coinex/ccxt/static_dependencies/mnemonic/wordlist/english.txt +2048 -0
- coinex/ccxt/static_dependencies/mnemonic/wordlist/french.txt +2048 -0
- coinex/ccxt/static_dependencies/mnemonic/wordlist/italian.txt +2048 -0
- coinex/ccxt/static_dependencies/mnemonic/wordlist/japanese.txt +2048 -0
- coinex/ccxt/static_dependencies/mnemonic/wordlist/korean.txt +2048 -0
- coinex/ccxt/static_dependencies/mnemonic/wordlist/portuguese.txt +2048 -0
- coinex/ccxt/static_dependencies/mnemonic/wordlist/russian.txt +2048 -0
- coinex/ccxt/static_dependencies/mnemonic/wordlist/spanish.txt +2048 -0
- coinex/ccxt/static_dependencies/mnemonic/wordlist/turkish.txt +2048 -0
- {coinex_api-0.0.89.dist-info → coinex_api-0.0.110.dist-info}/METADATA +3 -3
- {coinex_api-0.0.89.dist-info → coinex_api-0.0.110.dist-info}/RECORD +197 -17
- {coinex_api-0.0.89.dist-info → coinex_api-0.0.110.dist-info}/WHEEL +1 -1
coinex/ccxt/base/exchange.py
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
# -----------------------------------------------------------------------------
|
|
6
6
|
|
|
7
|
-
__version__ = '4.5.
|
|
7
|
+
__version__ = '4.5.25'
|
|
8
8
|
|
|
9
9
|
# -----------------------------------------------------------------------------
|
|
10
10
|
|
|
@@ -33,7 +33,7 @@ from ccxt.base.decimal_to_precision import decimal_to_precision
|
|
|
33
33
|
from ccxt.base.decimal_to_precision import DECIMAL_PLACES, TICK_SIZE, NO_PADDING, TRUNCATE, ROUND, ROUND_UP, ROUND_DOWN, SIGNIFICANT_DIGITS
|
|
34
34
|
from ccxt.base.decimal_to_precision import number_to_string
|
|
35
35
|
from ccxt.base.precise import Precise
|
|
36
|
-
from ccxt.base.types import ConstructorArgs, BalanceAccount, Currency, IndexType, OrderSide, OrderType, Trade, OrderRequest, Market, MarketType, Str, Num, Strings, CancellationRequest, Bool
|
|
36
|
+
from ccxt.base.types import ConstructorArgs, BalanceAccount, Currency, IndexType, OrderSide, OrderType, Trade, OrderRequest, Market, MarketType, Str, Num, Strings, CancellationRequest, Bool, Order
|
|
37
37
|
|
|
38
38
|
# -----------------------------------------------------------------------------
|
|
39
39
|
|
|
@@ -50,6 +50,11 @@ from cryptography.hazmat.primitives.serialization import load_pem_private_key
|
|
|
50
50
|
from ccxt.static_dependencies import ecdsa
|
|
51
51
|
from ccxt.static_dependencies import keccak
|
|
52
52
|
|
|
53
|
+
try:
|
|
54
|
+
import coincurve
|
|
55
|
+
except ImportError:
|
|
56
|
+
coincurve = None
|
|
57
|
+
|
|
53
58
|
# eddsa signing
|
|
54
59
|
try:
|
|
55
60
|
import axolotl_curve25519 as eddsa
|
|
@@ -67,6 +72,28 @@ from ccxt.static_dependencies.starknet.hash.address import compute_address
|
|
|
67
72
|
from ccxt.static_dependencies.starknet.hash.selector import get_selector_from_name
|
|
68
73
|
from ccxt.static_dependencies.starknet.hash.utils import message_signature, private_to_stark_key
|
|
69
74
|
from ccxt.static_dependencies.starknet.utils.typed_data import TypedData as TypedDataDataclass
|
|
75
|
+
|
|
76
|
+
# dydx
|
|
77
|
+
try:
|
|
78
|
+
from ccxt.static_dependencies.mnemonic import Mnemonic
|
|
79
|
+
from ccxt.static_dependencies.bip import Bip44
|
|
80
|
+
from ccxt.static_dependencies.dydx_v4_client.cosmos.tx.signing.v1beta1.signing_pb2 import SignMode
|
|
81
|
+
from ccxt.static_dependencies.dydx_v4_client.cosmos.tx.v1beta1.tx_pb2 import (
|
|
82
|
+
AuthInfo,
|
|
83
|
+
Fee,
|
|
84
|
+
ModeInfo,
|
|
85
|
+
SignDoc,
|
|
86
|
+
SignerInfo,
|
|
87
|
+
Tx,
|
|
88
|
+
TxBody,
|
|
89
|
+
TxRaw,
|
|
90
|
+
)
|
|
91
|
+
from ccxt.static_dependencies.dydx_v4_client.registry import (
|
|
92
|
+
encode_as_any,
|
|
93
|
+
)
|
|
94
|
+
except ImportError:
|
|
95
|
+
encode_as_any = None
|
|
96
|
+
|
|
70
97
|
try:
|
|
71
98
|
import apexpro.zklink_sdk as zklink_sdk
|
|
72
99
|
except ImportError:
|
|
@@ -311,8 +338,7 @@ class Exchange(object):
|
|
|
311
338
|
bidsasks = None
|
|
312
339
|
base_currencies = None
|
|
313
340
|
quote_currencies = None
|
|
314
|
-
currencies =
|
|
315
|
-
|
|
341
|
+
currencies = {}
|
|
316
342
|
options = None # Python does not allow to define properties in run-time with setattr
|
|
317
343
|
isSandboxModeEnabled = False
|
|
318
344
|
accounts = None
|
|
@@ -650,71 +676,66 @@ class Exchange(object):
|
|
|
650
676
|
|
|
651
677
|
@staticmethod
|
|
652
678
|
def key_exists(dictionary, key):
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
except LookupError:
|
|
660
|
-
return False
|
|
661
|
-
return False
|
|
679
|
+
try:
|
|
680
|
+
value = dictionary[key]
|
|
681
|
+
return value is not None and value != ''
|
|
682
|
+
except Exception:
|
|
683
|
+
# catch any exception, not only (KeyError, IndexError, TypeError):
|
|
684
|
+
return False
|
|
662
685
|
|
|
663
686
|
@staticmethod
|
|
664
687
|
def safe_float(dictionary, key, default_value=None):
|
|
665
|
-
value = default_value
|
|
666
688
|
try:
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
value = default_value
|
|
671
|
-
return value
|
|
689
|
+
return float(dictionary[key])
|
|
690
|
+
except Exception:
|
|
691
|
+
return default_value
|
|
672
692
|
|
|
673
693
|
@staticmethod
|
|
674
694
|
def safe_string(dictionary, key, default_value=None):
|
|
675
|
-
|
|
695
|
+
try:
|
|
696
|
+
value = dictionary[key]
|
|
697
|
+
if value is not None and value != '':
|
|
698
|
+
return str(value)
|
|
699
|
+
except Exception:
|
|
700
|
+
pass
|
|
701
|
+
return default_value
|
|
676
702
|
|
|
677
703
|
@staticmethod
|
|
678
704
|
def safe_string_lower(dictionary, key, default_value=None):
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
705
|
+
try:
|
|
706
|
+
value = dictionary[key]
|
|
707
|
+
if value is not None and value != '':
|
|
708
|
+
return str(value).lower()
|
|
709
|
+
except Exception:
|
|
710
|
+
pass
|
|
711
|
+
return default_value.lower() if default_value is not None else default_value
|
|
683
712
|
|
|
684
713
|
@staticmethod
|
|
685
714
|
def safe_string_upper(dictionary, key, default_value=None):
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
715
|
+
try:
|
|
716
|
+
value = dictionary[key]
|
|
717
|
+
if value is not None and value != '':
|
|
718
|
+
return str(value).upper()
|
|
719
|
+
except Exception:
|
|
720
|
+
pass
|
|
721
|
+
return default_value.upper() if default_value is not None else default_value
|
|
690
722
|
|
|
691
723
|
@staticmethod
|
|
692
724
|
def safe_integer(dictionary, key, default_value=None):
|
|
693
|
-
if not Exchange.key_exists(dictionary, key):
|
|
694
|
-
return default_value
|
|
695
|
-
value = dictionary[key]
|
|
696
725
|
try:
|
|
697
726
|
# needed to avoid breaking on "100.0"
|
|
698
727
|
# https://stackoverflow.com/questions/1094717/convert-a-string-to-integer-with-decimal-in-python#1094721
|
|
699
|
-
return int(float(
|
|
700
|
-
except
|
|
701
|
-
|
|
702
|
-
except TypeError:
|
|
728
|
+
return int(float(dictionary[key]))
|
|
729
|
+
except Exception:
|
|
730
|
+
# catch any exception, not only (KeyError, IndexError, TypeError, ValueError):
|
|
703
731
|
return default_value
|
|
704
732
|
|
|
705
733
|
@staticmethod
|
|
706
734
|
def safe_integer_product(dictionary, key, factor, default_value=None):
|
|
707
|
-
|
|
735
|
+
try:
|
|
736
|
+
return int(float(dictionary[key]) * factor)
|
|
737
|
+
except Exception:
|
|
708
738
|
return default_value
|
|
709
|
-
value = dictionary[key]
|
|
710
|
-
if isinstance(value, Number):
|
|
711
|
-
return int(value * factor)
|
|
712
|
-
elif isinstance(value, str):
|
|
713
|
-
try:
|
|
714
|
-
return int(float(value) * factor)
|
|
715
|
-
except ValueError:
|
|
716
|
-
pass
|
|
717
|
-
return default_value
|
|
718
739
|
|
|
719
740
|
@staticmethod
|
|
720
741
|
def safe_timestamp(dictionary, key, default_value=None):
|
|
@@ -722,35 +743,72 @@ class Exchange(object):
|
|
|
722
743
|
|
|
723
744
|
@staticmethod
|
|
724
745
|
def safe_value(dictionary, key, default_value=None):
|
|
725
|
-
|
|
746
|
+
try:
|
|
747
|
+
value = dictionary[key]
|
|
748
|
+
if value is not None and value != '':
|
|
749
|
+
return value
|
|
750
|
+
except Exception:
|
|
751
|
+
pass
|
|
752
|
+
return default_value
|
|
726
753
|
|
|
727
754
|
# we're not using safe_floats with a list argument as we're trying to save some cycles here
|
|
728
755
|
# we're not using safe_float_3 either because those cases are too rare to deserve their own optimization
|
|
729
756
|
|
|
730
757
|
@staticmethod
|
|
731
758
|
def safe_float_2(dictionary, key1, key2, default_value=None):
|
|
732
|
-
|
|
759
|
+
try:
|
|
760
|
+
return float(dictionary[key1])
|
|
761
|
+
except Exception:
|
|
762
|
+
try:
|
|
763
|
+
return float(dictionary[key2])
|
|
764
|
+
except Exception:
|
|
765
|
+
return default_value
|
|
733
766
|
|
|
734
767
|
@staticmethod
|
|
735
768
|
def safe_string_2(dictionary, key1, key2, default_value=None):
|
|
736
|
-
|
|
769
|
+
try:
|
|
770
|
+
value = dictionary[key1]
|
|
771
|
+
if value is not None and value != '':
|
|
772
|
+
return str(value)
|
|
773
|
+
except Exception:
|
|
774
|
+
pass
|
|
775
|
+
try:
|
|
776
|
+
value = dictionary[key2]
|
|
777
|
+
if value is not None and value != '':
|
|
778
|
+
return str(value)
|
|
779
|
+
except Exception:
|
|
780
|
+
pass
|
|
781
|
+
return default_value
|
|
737
782
|
|
|
738
783
|
@staticmethod
|
|
739
784
|
def safe_string_lower_2(dictionary, key1, key2, default_value=None):
|
|
740
|
-
|
|
785
|
+
value = Exchange.safe_string_2(dictionary, key1, key2, default_value)
|
|
786
|
+
return value.lower() if value is not None else value
|
|
741
787
|
|
|
742
788
|
@staticmethod
|
|
743
789
|
def safe_string_upper_2(dictionary, key1, key2, default_value=None):
|
|
744
|
-
|
|
790
|
+
value = Exchange.safe_string_2(dictionary, key1, key2, default_value)
|
|
791
|
+
return value.upper() if value is not None else value
|
|
745
792
|
|
|
746
793
|
@staticmethod
|
|
747
794
|
def safe_integer_2(dictionary, key1, key2, default_value=None):
|
|
748
|
-
|
|
795
|
+
try:
|
|
796
|
+
return int(float(dictionary[key1]))
|
|
797
|
+
except Exception:
|
|
798
|
+
try:
|
|
799
|
+
return int(float(dictionary[key2]))
|
|
800
|
+
except Exception:
|
|
801
|
+
return default_value
|
|
749
802
|
|
|
750
803
|
@staticmethod
|
|
751
804
|
def safe_integer_product_2(dictionary, key1, key2, factor, default_value=None):
|
|
752
|
-
|
|
753
|
-
|
|
805
|
+
try:
|
|
806
|
+
return int(float(dictionary[key1]) * factor)
|
|
807
|
+
except Exception:
|
|
808
|
+
try:
|
|
809
|
+
return int(float(dictionary[key2]) * factor)
|
|
810
|
+
except Exception:
|
|
811
|
+
return default_value
|
|
754
812
|
|
|
755
813
|
@staticmethod
|
|
756
814
|
def safe_timestamp_2(dictionary, key1, key2, default_value=None):
|
|
@@ -758,7 +816,19 @@ class Exchange(object):
|
|
|
758
816
|
|
|
759
817
|
@staticmethod
|
|
760
818
|
def safe_value_2(dictionary, key1, key2, default_value=None):
|
|
761
|
-
|
|
819
|
+
try:
|
|
820
|
+
value = dictionary[key1]
|
|
821
|
+
if value is not None and value != '':
|
|
822
|
+
return value
|
|
823
|
+
except Exception:
|
|
824
|
+
pass
|
|
825
|
+
try:
|
|
826
|
+
value = dictionary[key2]
|
|
827
|
+
if value is not None and value != '':
|
|
828
|
+
return value
|
|
829
|
+
except Exception:
|
|
830
|
+
pass
|
|
831
|
+
return default_value
|
|
762
832
|
|
|
763
833
|
# safe_method_n methods family
|
|
764
834
|
|
|
@@ -768,10 +838,9 @@ class Exchange(object):
|
|
|
768
838
|
if value is None:
|
|
769
839
|
return default_value
|
|
770
840
|
try:
|
|
771
|
-
|
|
841
|
+
return float(value)
|
|
772
842
|
except ValueError as e:
|
|
773
|
-
|
|
774
|
-
return value
|
|
843
|
+
return default_value
|
|
775
844
|
|
|
776
845
|
@staticmethod
|
|
777
846
|
def safe_string_n(dictionary, key_list, default_value=None):
|
|
@@ -892,6 +961,10 @@ class Exchange(object):
|
|
|
892
961
|
def uuidv1():
|
|
893
962
|
return str(uuid.uuid1()).replace('-', '')
|
|
894
963
|
|
|
964
|
+
@staticmethod
|
|
965
|
+
def uuid5(namespace: str, name):
|
|
966
|
+
return str(uuid.uuid5(uuid.UUID(namespace), name))
|
|
967
|
+
|
|
895
968
|
@staticmethod
|
|
896
969
|
def capitalize(string): # first character only, rest characters unchanged
|
|
897
970
|
# the native pythonic .capitalize() method lowercases all other characters
|
|
@@ -1356,7 +1429,7 @@ class Exchange(object):
|
|
|
1356
1429
|
)
|
|
1357
1430
|
return {
|
|
1358
1431
|
'privateKey': privateKey,
|
|
1359
|
-
'publicKey': publicKey,
|
|
1432
|
+
'publicKey': hex(publicKey),
|
|
1360
1433
|
'address': hex(address)
|
|
1361
1434
|
}
|
|
1362
1435
|
|
|
@@ -1385,6 +1458,8 @@ class Exchange(object):
|
|
|
1385
1458
|
@staticmethod
|
|
1386
1459
|
def starknet_sign (msg_hash, pri):
|
|
1387
1460
|
# // TODO: unify to ecdsa
|
|
1461
|
+
if isinstance(pri, str):
|
|
1462
|
+
pri = int(pri, 16)
|
|
1388
1463
|
r, s = message_signature(msg_hash, pri)
|
|
1389
1464
|
return Exchange.json([hex(r), hex(s)])
|
|
1390
1465
|
|
|
@@ -1402,6 +1477,21 @@ class Exchange(object):
|
|
|
1402
1477
|
|
|
1403
1478
|
@staticmethod
|
|
1404
1479
|
def ecdsa(request, secret, algorithm='p256', hash=None, fixed_length=False):
|
|
1480
|
+
"""
|
|
1481
|
+
ECDSA signing with support for multiple algorithms and coincurve for SECP256K1.
|
|
1482
|
+
Args:
|
|
1483
|
+
request: The message to sign
|
|
1484
|
+
secret: The private key (hex string or PEM format)
|
|
1485
|
+
algorithm: The elliptic curve algorithm ('p192', 'p224', 'p256', 'p384', 'p521', 'secp256k1')
|
|
1486
|
+
hash: The hash function to use (defaults to algorithm-specific hash)
|
|
1487
|
+
fixed_length: Whether to ensure fixed-length signatures (for deterministic signing)
|
|
1488
|
+
Note: coincurve produces non-deterministic signatures
|
|
1489
|
+
Returns:
|
|
1490
|
+
dict: {'r': r_value, 's': s_value, 'v': v_value}
|
|
1491
|
+
Note:
|
|
1492
|
+
If coincurve is not available or fails for SECP256K1, the method automatically
|
|
1493
|
+
falls back to the standard ecdsa implementation.
|
|
1494
|
+
"""
|
|
1405
1495
|
# your welcome - frosty00
|
|
1406
1496
|
algorithms = {
|
|
1407
1497
|
'p192': [ecdsa.NIST192p, 'sha256'],
|
|
@@ -1413,6 +1503,14 @@ class Exchange(object):
|
|
|
1413
1503
|
}
|
|
1414
1504
|
if algorithm not in algorithms:
|
|
1415
1505
|
raise ArgumentsRequired(algorithm + ' is not a supported algorithm')
|
|
1506
|
+
# Use coincurve for SECP256K1 if available
|
|
1507
|
+
if algorithm == 'secp256k1' and coincurve is not None:
|
|
1508
|
+
try:
|
|
1509
|
+
return Exchange._ecdsa_secp256k1_coincurve(request, secret, hash, fixed_length)
|
|
1510
|
+
except Exception:
|
|
1511
|
+
# If coincurve fails, fall back to ecdsa implementation
|
|
1512
|
+
pass
|
|
1513
|
+
# Fall back to original ecdsa implementation for other algorithms or when deterministic signing is needed
|
|
1416
1514
|
curve_info = algorithms[algorithm]
|
|
1417
1515
|
hash_function = getattr(hashlib, curve_info[1])
|
|
1418
1516
|
encoded_request = Exchange.encode(request)
|
|
@@ -1448,6 +1546,53 @@ class Exchange(object):
|
|
|
1448
1546
|
|
|
1449
1547
|
|
|
1450
1548
|
@staticmethod
|
|
1549
|
+
def _ecdsa_secp256k1_coincurve(request, secret, hash=None, fixed_length=False):
|
|
1550
|
+
"""
|
|
1551
|
+
Use coincurve library for SECP256K1 ECDSA signing.
|
|
1552
|
+
This method provides faster SECP256K1 signing using the coincurve library,
|
|
1553
|
+
which is a Python binding to libsecp256k1. This implementation produces
|
|
1554
|
+
deterministic signatures (RFC 6979) using coincurve's sign_recoverable method.
|
|
1555
|
+
Args:
|
|
1556
|
+
request: The message to sign
|
|
1557
|
+
secret: The private key (hex string or PEM format)
|
|
1558
|
+
hash: The hash function to use
|
|
1559
|
+
fixed_length: Not used in coincurve implementation (signatures are always fixed length)
|
|
1560
|
+
Returns:
|
|
1561
|
+
dict: {'r': r_value, 's': s_value, 'v': v_value}
|
|
1562
|
+
Raises:
|
|
1563
|
+
ArgumentsRequired: If coincurve library is not available
|
|
1564
|
+
"""
|
|
1565
|
+
encoded_request = Exchange.encode(request)
|
|
1566
|
+
if hash is not None:
|
|
1567
|
+
digest = Exchange.hash(encoded_request, hash, 'binary')
|
|
1568
|
+
else:
|
|
1569
|
+
digest = base64.b16decode(encoded_request, casefold=True)
|
|
1570
|
+
if isinstance(secret, str):
|
|
1571
|
+
secret = Exchange.encode(secret)
|
|
1572
|
+
# Handle PEM format
|
|
1573
|
+
if secret.find(b'-----BEGIN EC PRIVATE KEY-----') > -1:
|
|
1574
|
+
secret = base64.b16decode(secret.replace(b'-----BEGIN EC PRIVATE KEY-----', b'').replace(b'-----END EC PRIVATE KEY-----', b'').replace(b'\n', b'').replace(b'\r', b''), casefold=True)
|
|
1575
|
+
else:
|
|
1576
|
+
# Assume hex format
|
|
1577
|
+
secret = base64.b16decode(secret, casefold=True)
|
|
1578
|
+
# Create coincurve PrivateKey
|
|
1579
|
+
private_key = coincurve.PrivateKey(secret)
|
|
1580
|
+
# Sign the digest using sign_recoverable which produces deterministic signatures (RFC 6979)
|
|
1581
|
+
# The signature format is: 32 bytes r + 32 bytes s + 1 byte recovery_id (v)
|
|
1582
|
+
signature = private_key.sign_recoverable(digest, hasher=None)
|
|
1583
|
+
# Extract r, s, and v from the recoverable signature (65 bytes total)
|
|
1584
|
+
r_binary = signature[:32]
|
|
1585
|
+
s_binary = signature[32:64]
|
|
1586
|
+
v = signature[64]
|
|
1587
|
+
# Convert to hex strings
|
|
1588
|
+
r = Exchange.decode(base64.b16encode(r_binary)).lower()
|
|
1589
|
+
s = Exchange.decode(base64.b16encode(s_binary)).lower()
|
|
1590
|
+
return {
|
|
1591
|
+
'r': r,
|
|
1592
|
+
's': s,
|
|
1593
|
+
'v': v,
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1451
1596
|
def binary_to_urlencoded_base64(data: bytes) -> str:
|
|
1452
1597
|
encoded = base64.urlsafe_b64encode(data).decode("utf-8")
|
|
1453
1598
|
return encoded.rstrip("=")
|
|
@@ -1479,9 +1624,10 @@ class Exchange(object):
|
|
|
1479
1624
|
|
|
1480
1625
|
@staticmethod
|
|
1481
1626
|
def is_json_encoded_object(input):
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1627
|
+
try:
|
|
1628
|
+
return (isinstance(input, str) and ((input[0] == '{') or (input[0] == '[')))
|
|
1629
|
+
except Exception:
|
|
1630
|
+
return False
|
|
1485
1631
|
|
|
1486
1632
|
@staticmethod
|
|
1487
1633
|
def encode(string):
|
|
@@ -1879,6 +2025,121 @@ class Exchange(object):
|
|
|
1879
2025
|
def is_binary_message(self, message):
|
|
1880
2026
|
return isinstance(message, bytes) or isinstance(message, bytearray)
|
|
1881
2027
|
|
|
2028
|
+
def retrieve_dydx_credentials(self, entropy):
|
|
2029
|
+
mnemo = Mnemonic("english")
|
|
2030
|
+
if ' ' in entropy:
|
|
2031
|
+
mnemonic = entropy
|
|
2032
|
+
else:
|
|
2033
|
+
mnemonic = mnemo.to_mnemonic(self.base16_to_binary(entropy))
|
|
2034
|
+
seed = mnemo.to_seed(mnemonic)
|
|
2035
|
+
keyPair = Bip44.FromSeed(seed).DeriveDefaultPath()
|
|
2036
|
+
privateKey = keyPair.PrivateKey().Raw().ToBytes()
|
|
2037
|
+
publicKey = keyPair.PublicKey().RawCompressed().ToBytes()
|
|
2038
|
+
return {
|
|
2039
|
+
'mnemonic': mnemonic,
|
|
2040
|
+
'privateKey': privateKey,
|
|
2041
|
+
'publicKey': publicKey,
|
|
2042
|
+
}
|
|
2043
|
+
|
|
2044
|
+
def load_dydx_protos(self):
|
|
2045
|
+
return
|
|
2046
|
+
|
|
2047
|
+
def to_dydx_long(self, num):
|
|
2048
|
+
return num
|
|
2049
|
+
|
|
2050
|
+
def encode_dydx_tx_for_simulation(self, message, memo, sequence, publicKey):
|
|
2051
|
+
if not encode_as_any:
|
|
2052
|
+
raise NotSupported(self.id + ' requires protobuf to encode messages, please install it with `pip install "protobuf==5.29.5"`')
|
|
2053
|
+
messages = [
|
|
2054
|
+
encode_as_any(
|
|
2055
|
+
message,
|
|
2056
|
+
)
|
|
2057
|
+
]
|
|
2058
|
+
body = TxBody(
|
|
2059
|
+
messages=messages,
|
|
2060
|
+
memo=memo,
|
|
2061
|
+
)
|
|
2062
|
+
auth_info = AuthInfo(
|
|
2063
|
+
signer_infos=[
|
|
2064
|
+
SignerInfo(
|
|
2065
|
+
public_key=encode_as_any({
|
|
2066
|
+
'typeUrl': '/cosmos.crypto.secp256k1.PubKey',
|
|
2067
|
+
'value': publicKey,
|
|
2068
|
+
}),
|
|
2069
|
+
sequence=self.parse_to_int(sequence),
|
|
2070
|
+
mode_info=ModeInfo(single=ModeInfo.Single(mode=SignMode.SIGN_MODE_UNSPECIFIED))
|
|
2071
|
+
)
|
|
2072
|
+
],
|
|
2073
|
+
fee={},
|
|
2074
|
+
)
|
|
2075
|
+
tx = Tx(body=body, auth_info=auth_info, signatures=[b''])
|
|
2076
|
+
return self.binary_to_base64(tx.SerializeToString())
|
|
2077
|
+
|
|
2078
|
+
def encode_dydx_tx_for_signing(self, message, memo, chainId, account, authenticators, fee=None):
|
|
2079
|
+
if not encode_as_any:
|
|
2080
|
+
raise NotSupported(self.id + ' requires protobuf to encode messages, please install it with `pip install "protobuf==5.29.5"`')
|
|
2081
|
+
if fee is None:
|
|
2082
|
+
fee = {
|
|
2083
|
+
'amount': [],
|
|
2084
|
+
'gasLimit': 1000000,
|
|
2085
|
+
}
|
|
2086
|
+
non_critical_extension_options = []
|
|
2087
|
+
if authenticators is not None:
|
|
2088
|
+
non_critical_extension_options.append(encode_as_any({
|
|
2089
|
+
'typeUrl': '/dydxprotocol.accountplus.TxExtension',
|
|
2090
|
+
'value': {
|
|
2091
|
+
'selected_authenticators': authenticators
|
|
2092
|
+
}
|
|
2093
|
+
}))
|
|
2094
|
+
messages = [
|
|
2095
|
+
encode_as_any(
|
|
2096
|
+
message
|
|
2097
|
+
)
|
|
2098
|
+
]
|
|
2099
|
+
sequence = self.milliseconds()
|
|
2100
|
+
body = TxBody(
|
|
2101
|
+
messages=messages,
|
|
2102
|
+
memo=memo,
|
|
2103
|
+
non_critical_extension_options=non_critical_extension_options,
|
|
2104
|
+
)
|
|
2105
|
+
auth_info = AuthInfo(
|
|
2106
|
+
signer_infos=[
|
|
2107
|
+
SignerInfo(
|
|
2108
|
+
public_key=encode_as_any({
|
|
2109
|
+
'typeUrl': '/cosmos.crypto.secp256k1.PubKey',
|
|
2110
|
+
'value': account['pub_key'],
|
|
2111
|
+
}),
|
|
2112
|
+
sequence=self.parse_to_int(sequence),
|
|
2113
|
+
mode_info=ModeInfo(single=ModeInfo.Single(mode=SignMode.SIGN_MODE_DIRECT))
|
|
2114
|
+
)
|
|
2115
|
+
],
|
|
2116
|
+
fee=Fee(amount=fee['amount'], gas_limit=fee['gasLimit']),
|
|
2117
|
+
)
|
|
2118
|
+
signDoc = SignDoc(
|
|
2119
|
+
account_number=self.parse_to_int(account['account_number']),
|
|
2120
|
+
auth_info_bytes=auth_info.SerializeToString(),
|
|
2121
|
+
body_bytes=body.SerializeToString(),
|
|
2122
|
+
chain_id=chainId,
|
|
2123
|
+
)
|
|
2124
|
+
signingHash = self.hash(signDoc.SerializeToString(), 'sha256', 'hex')
|
|
2125
|
+
return [signingHash, signDoc]
|
|
2126
|
+
|
|
2127
|
+
def encode_dydx_tx_raw(self, signDoc, signature):
|
|
2128
|
+
if not encode_as_any:
|
|
2129
|
+
raise NotSupported(self.id + ' requires protobuf to encode messages, please install it with `pip install "protobuf==5.29.5"`')
|
|
2130
|
+
tx = TxRaw(
|
|
2131
|
+
auth_info_bytes=signDoc.auth_info_bytes,
|
|
2132
|
+
body_bytes=signDoc.body_bytes,
|
|
2133
|
+
signatures=[self.base16ToBinary(signature)],
|
|
2134
|
+
)
|
|
2135
|
+
return '0x' + self.binary_to_base16(tx.SerializeToString())
|
|
2136
|
+
|
|
2137
|
+
def lock_id(self):
|
|
2138
|
+
return None
|
|
2139
|
+
|
|
2140
|
+
def unlock_id(self):
|
|
2141
|
+
return None
|
|
2142
|
+
|
|
1882
2143
|
# ########################################################################
|
|
1883
2144
|
# ########################################################################
|
|
1884
2145
|
# ########################################################################
|
|
@@ -1947,8 +2208,10 @@ class Exchange(object):
|
|
|
1947
2208
|
'cancelAllOrders': None,
|
|
1948
2209
|
'cancelAllOrdersWs': None,
|
|
1949
2210
|
'cancelOrder': True,
|
|
2211
|
+
'cancelOrderWithClientOrderId': None,
|
|
1950
2212
|
'cancelOrderWs': None,
|
|
1951
2213
|
'cancelOrders': None,
|
|
2214
|
+
'cancelOrdersWithClientOrderId': None,
|
|
1952
2215
|
'cancelOrdersWs': None,
|
|
1953
2216
|
'closeAllPositions': None,
|
|
1954
2217
|
'closePosition': None,
|
|
@@ -1998,6 +2261,7 @@ class Exchange(object):
|
|
|
1998
2261
|
'createTriggerOrderWs': None,
|
|
1999
2262
|
'deposit': None,
|
|
2000
2263
|
'editOrder': 'emulated',
|
|
2264
|
+
'editOrderWithClientOrderId': None,
|
|
2001
2265
|
'editOrders': None,
|
|
2002
2266
|
'editOrderWs': None,
|
|
2003
2267
|
'fetchAccounts': None,
|
|
@@ -2076,6 +2340,7 @@ class Exchange(object):
|
|
|
2076
2340
|
'fetchOption': None,
|
|
2077
2341
|
'fetchOptionChain': None,
|
|
2078
2342
|
'fetchOrder': None,
|
|
2343
|
+
'fetchOrderWithClientOrderId': None,
|
|
2079
2344
|
'fetchOrderBook': True,
|
|
2080
2345
|
'fetchOrderBooks': None,
|
|
2081
2346
|
'fetchOrderBookWs': None,
|
|
@@ -2285,9 +2550,8 @@ class Exchange(object):
|
|
|
2285
2550
|
value = self.safe_value_n(dictionaryOrList, keys, defaultValue)
|
|
2286
2551
|
if value is None:
|
|
2287
2552
|
return defaultValue
|
|
2288
|
-
if
|
|
2289
|
-
|
|
2290
|
-
return value
|
|
2553
|
+
if isinstance(value, dict):
|
|
2554
|
+
return value
|
|
2291
2555
|
return defaultValue
|
|
2292
2556
|
|
|
2293
2557
|
def safe_dict(self, dictionary, key: IndexType, defaultValue: dict = None):
|
|
@@ -2348,7 +2612,7 @@ class Exchange(object):
|
|
|
2348
2612
|
bookSide.storeArray(bidAsk)
|
|
2349
2613
|
|
|
2350
2614
|
def get_cache_index(self, orderbook, deltas):
|
|
2351
|
-
# return the first index of the cache that can be applied to the orderbook or -1 if not possible
|
|
2615
|
+
# return the first index of the cache that can be applied to the orderbook or -1 if not possible.
|
|
2352
2616
|
return -1
|
|
2353
2617
|
|
|
2354
2618
|
def arrays_concat(self, arraysOfArrays: List[Any]):
|
|
@@ -2591,6 +2855,22 @@ class Exchange(object):
|
|
|
2591
2855
|
# set flag
|
|
2592
2856
|
self.isSandboxModeEnabled = False
|
|
2593
2857
|
|
|
2858
|
+
def enable_demo_trading(self, enable: bool):
|
|
2859
|
+
"""
|
|
2860
|
+
enables or disables demo trading mode
|
|
2861
|
+
:param boolean [enable]: True if demo trading should be enabled, False otherwise
|
|
2862
|
+
"""
|
|
2863
|
+
if self.isSandboxModeEnabled:
|
|
2864
|
+
raise NotSupported(self.id + ' demo trading does not support in sandbox environment. Please check https://www.binance.com/en/support/faq/detail/9be58f73e5e14338809e3b705b9687dd to see the differences')
|
|
2865
|
+
if enable:
|
|
2866
|
+
self.urls['apiBackupDemoTrading'] = self.urls['api']
|
|
2867
|
+
self.urls['api'] = self.urls['demo']
|
|
2868
|
+
elif 'apiBackupDemoTrading' in self.urls:
|
|
2869
|
+
self.urls['api'] = self.urls['apiBackupDemoTrading']
|
|
2870
|
+
newUrls = self.omit(self.urls, 'apiBackupDemoTrading')
|
|
2871
|
+
self.urls = newUrls
|
|
2872
|
+
self.options['enableDemoTrading'] = enable
|
|
2873
|
+
|
|
2594
2874
|
def sign(self, path, api: Any = 'public', method='GET', params={}, headers: Any = None, body: Any = None):
|
|
2595
2875
|
return {}
|
|
2596
2876
|
|
|
@@ -2658,6 +2938,12 @@ class Exchange(object):
|
|
|
2658
2938
|
def un_watch_ticker(self, symbol: str, params={}):
|
|
2659
2939
|
raise NotSupported(self.id + ' unWatchTicker() is not supported yet')
|
|
2660
2940
|
|
|
2941
|
+
def un_watch_mark_price(self, symbol: str, params={}):
|
|
2942
|
+
raise NotSupported(self.id + ' unWatchMarkPrice() is not supported yet')
|
|
2943
|
+
|
|
2944
|
+
def un_watch_mark_prices(self, symbols: Strings = None, params={}):
|
|
2945
|
+
raise NotSupported(self.id + ' unWatchMarkPrices() is not supported yet')
|
|
2946
|
+
|
|
2661
2947
|
def fetch_deposit_addresses(self, codes: Strings = None, params={}):
|
|
2662
2948
|
raise NotSupported(self.id + ' fetchDepositAddresses() is not supported yet')
|
|
2663
2949
|
|
|
@@ -2927,7 +3213,7 @@ class Exchange(object):
|
|
|
2927
3213
|
'delay': 0.001,
|
|
2928
3214
|
'capacity': 1,
|
|
2929
3215
|
'cost': 1,
|
|
2930
|
-
'maxCapacity': 1000,
|
|
3216
|
+
'maxCapacity': self.safe_integer(self.options, 'maxRequestsQueue', 1000),
|
|
2931
3217
|
'refillRate': refillRate,
|
|
2932
3218
|
}
|
|
2933
3219
|
existingBucket = {} if (self.tokenBucket is None) else self.tokenBucket
|
|
@@ -3009,6 +3295,79 @@ class Exchange(object):
|
|
|
3009
3295
|
featureBlock['symbolRequired'] = self.in_array(key, ['createOrder', 'createOrders', 'fetchOHLCV'])
|
|
3010
3296
|
return featuresObj
|
|
3011
3297
|
|
|
3298
|
+
def feature_value(self, symbol: str, methodName: Str = None, paramName: Str = None, defaultValue: Any = None):
|
|
3299
|
+
"""
|
|
3300
|
+
self method is a very deterministic to help users to know what feature is supported by the exchange
|
|
3301
|
+
:param str [symbol]: unified symbol
|
|
3302
|
+
:param str [methodName]: view currently supported methods: https://docs.ccxt.com/#/README?id=features
|
|
3303
|
+
:param str [paramName]: unified param value, like: `triggerPrice`, `stopLoss.triggerPrice`(check docs for supported param names)
|
|
3304
|
+
:param dict [defaultValue]: return default value if no result found
|
|
3305
|
+
:returns dict: returns feature value
|
|
3306
|
+
"""
|
|
3307
|
+
market = self.market(symbol)
|
|
3308
|
+
return self.feature_value_by_type(market['type'], market['subType'], methodName, paramName, defaultValue)
|
|
3309
|
+
|
|
3310
|
+
def feature_value_by_type(self, marketType: str, subType: Str, methodName: Str = None, paramName: Str = None, defaultValue: Any = None):
|
|
3311
|
+
"""
|
|
3312
|
+
self method is a very deterministic to help users to know what feature is supported by the exchange
|
|
3313
|
+
:param str [marketType]: supported only: "spot", "swap", "future"
|
|
3314
|
+
:param str [subType]: supported only: "linear", "inverse"
|
|
3315
|
+
:param str [methodName]: view currently supported methods: https://docs.ccxt.com/#/README?id=features
|
|
3316
|
+
:param str [paramName]: unified param value(check docs for supported param names)
|
|
3317
|
+
:param dict [defaultValue]: return default value if no result found
|
|
3318
|
+
:returns dict: returns feature value
|
|
3319
|
+
"""
|
|
3320
|
+
# if exchange does not yet have features manually implemented
|
|
3321
|
+
if self.features is None:
|
|
3322
|
+
return defaultValue
|
|
3323
|
+
if marketType is None:
|
|
3324
|
+
return defaultValue # marketType is required
|
|
3325
|
+
# if marketType(e.g. 'option') does not exist in features
|
|
3326
|
+
if not (marketType in self.features):
|
|
3327
|
+
return defaultValue # unsupported marketType, check "exchange.features" for details
|
|
3328
|
+
# if marketType dict None
|
|
3329
|
+
if self.features[marketType] is None:
|
|
3330
|
+
return defaultValue
|
|
3331
|
+
methodsContainer = self.features[marketType]
|
|
3332
|
+
if subType is None:
|
|
3333
|
+
if marketType != 'spot':
|
|
3334
|
+
return defaultValue # subType is required for non-spot markets
|
|
3335
|
+
else:
|
|
3336
|
+
if not (subType in self.features[marketType]):
|
|
3337
|
+
return defaultValue # unsupported subType, check "exchange.features" for details
|
|
3338
|
+
# if subType dict None
|
|
3339
|
+
if self.features[marketType][subType] is None:
|
|
3340
|
+
return defaultValue
|
|
3341
|
+
methodsContainer = self.features[marketType][subType]
|
|
3342
|
+
# if user wanted only marketType and didn't provide methodName, eg: featureIsSupported('spot')
|
|
3343
|
+
if methodName is None:
|
|
3344
|
+
return defaultValue if (defaultValue is not None) else methodsContainer
|
|
3345
|
+
if not (methodName in methodsContainer):
|
|
3346
|
+
return defaultValue # unsupported method, check "exchange.features" for details')
|
|
3347
|
+
methodDict = methodsContainer[methodName]
|
|
3348
|
+
if methodDict is None:
|
|
3349
|
+
return defaultValue
|
|
3350
|
+
# if user wanted only method and didn't provide `paramName`, eg: featureIsSupported('swap', 'linear', 'createOrder')
|
|
3351
|
+
if paramName is None:
|
|
3352
|
+
return defaultValue if (defaultValue is not None) else methodDict
|
|
3353
|
+
splited = paramName.split('.') # can be only parent key(`stopLoss`) or with child(`stopLoss.triggerPrice`)
|
|
3354
|
+
parentKey = splited[0]
|
|
3355
|
+
subKey = self.safe_string(splited, 1)
|
|
3356
|
+
if not (parentKey in methodDict):
|
|
3357
|
+
return defaultValue # unsupported paramName, check "exchange.features" for details')
|
|
3358
|
+
dictionary = self.safe_dict(methodDict, parentKey)
|
|
3359
|
+
if dictionary is None:
|
|
3360
|
+
# if the value is not dictionary but a scalar value(or None), return
|
|
3361
|
+
return methodDict[parentKey]
|
|
3362
|
+
else:
|
|
3363
|
+
# return, when calling without subKey eg: featureValueByType('spot', None, 'createOrder', 'stopLoss')
|
|
3364
|
+
if subKey is None:
|
|
3365
|
+
return methodDict[parentKey]
|
|
3366
|
+
# raise an exception for unsupported subKey
|
|
3367
|
+
if not (subKey in methodDict[parentKey]):
|
|
3368
|
+
return defaultValue # unsupported subKey, check "exchange.features" for details
|
|
3369
|
+
return methodDict[parentKey][subKey]
|
|
3370
|
+
|
|
3012
3371
|
def orderbook_checksum_message(self, symbol: Str):
|
|
3013
3372
|
return symbol + ' = False'
|
|
3014
3373
|
|
|
@@ -3275,7 +3634,11 @@ class Exchange(object):
|
|
|
3275
3634
|
marketsSortedById = self.keysort(self.markets_by_id)
|
|
3276
3635
|
self.symbols = list(marketsSortedBySymbol.keys())
|
|
3277
3636
|
self.ids = list(marketsSortedById.keys())
|
|
3637
|
+
numCurrencies = 0
|
|
3278
3638
|
if currencies is not None:
|
|
3639
|
+
keys = list(currencies.keys())
|
|
3640
|
+
numCurrencies = len(keys)
|
|
3641
|
+
if numCurrencies > 0:
|
|
3279
3642
|
# currencies is always None when called in constructor but not when called from loadMarkets
|
|
3280
3643
|
self.currencies = self.map_to_safe_map(self.deep_extend(self.currencies, currencies))
|
|
3281
3644
|
else:
|
|
@@ -3340,6 +3703,7 @@ class Exchange(object):
|
|
|
3340
3703
|
self.symbols = sourceExchange.symbols
|
|
3341
3704
|
self.ids = sourceExchange.ids
|
|
3342
3705
|
self.currencies = sourceExchange.currencies
|
|
3706
|
+
self.currencies_by_id = sourceExchange.currencies_by_id
|
|
3343
3707
|
self.baseCurrencies = sourceExchange.baseCurrencies
|
|
3344
3708
|
self.quoteCurrencies = sourceExchange.quoteCurrencies
|
|
3345
3709
|
self.codes = sourceExchange.codes
|
|
@@ -3767,7 +4131,7 @@ class Exchange(object):
|
|
|
3767
4131
|
if feeDefined:
|
|
3768
4132
|
fee = self.parse_fee_numeric(fee)
|
|
3769
4133
|
if not feesDefined:
|
|
3770
|
-
# just set it directly, no further processing needed
|
|
4134
|
+
# just set it directly, no further processing needed.
|
|
3771
4135
|
fees = [fee]
|
|
3772
4136
|
# 'fees' were set, so reparse them
|
|
3773
4137
|
reducedFees = self.reduce_fees_by_currency(fees) if self.reduceFees else fees
|
|
@@ -4613,7 +4977,8 @@ class Exchange(object):
|
|
|
4613
4977
|
if isinstance(e, OperationFailed):
|
|
4614
4978
|
if i < retries:
|
|
4615
4979
|
if self.verbose:
|
|
4616
|
-
|
|
4980
|
+
index = i + 1
|
|
4981
|
+
self.log('Request failed with the error: ' + str(e) + ', retrying ' + str(index) + ' of ' + str(retries) + '...')
|
|
4617
4982
|
if (retryDelay is not None) and (retryDelay != 0):
|
|
4618
4983
|
self.sleep(retryDelay)
|
|
4619
4984
|
else:
|
|
@@ -4650,9 +5015,12 @@ class Exchange(object):
|
|
|
4650
5015
|
i_count = 6
|
|
4651
5016
|
tradesLength = len(trades)
|
|
4652
5017
|
oldest = min(tradesLength, limit)
|
|
5018
|
+
options = self.safe_dict(self.options, 'buildOHLCVC', {})
|
|
5019
|
+
skipZeroPrices = self.safe_bool(options, 'skipZeroPrices', True)
|
|
4653
5020
|
for i in range(0, oldest):
|
|
4654
5021
|
trade = trades[i]
|
|
4655
5022
|
ts = trade['timestamp']
|
|
5023
|
+
price = trade['price']
|
|
4656
5024
|
if ts < since:
|
|
4657
5025
|
continue
|
|
4658
5026
|
openingTime = int(math.floor(ts / ms)) * ms # shift to the edge of m/h/d(but not M)
|
|
@@ -4660,22 +5028,25 @@ class Exchange(object):
|
|
|
4660
5028
|
continue
|
|
4661
5029
|
ohlcv_length = len(ohlcvs)
|
|
4662
5030
|
candle = ohlcv_length - 1
|
|
4663
|
-
if (
|
|
5031
|
+
if skipZeroPrices and not (price > 0) and not (price < 0):
|
|
5032
|
+
continue
|
|
5033
|
+
isFirstCandle = candle == -1
|
|
5034
|
+
if isFirstCandle or openingTime >= self.sum(ohlcvs[candle][i_timestamp], ms):
|
|
4664
5035
|
# moved to a new timeframe -> create a new candle from opening trade
|
|
4665
5036
|
ohlcvs.append([
|
|
4666
5037
|
openingTime, # timestamp
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
5038
|
+
price, # O
|
|
5039
|
+
price, # H
|
|
5040
|
+
price, # L
|
|
5041
|
+
price, # C
|
|
4671
5042
|
trade['amount'], # V
|
|
4672
5043
|
1, # count
|
|
4673
5044
|
])
|
|
4674
5045
|
else:
|
|
4675
5046
|
# still processing the same timeframe -> update opening trade
|
|
4676
|
-
ohlcvs[candle][i_high] = max(ohlcvs[candle][i_high],
|
|
4677
|
-
ohlcvs[candle][i_low] = min(ohlcvs[candle][i_low],
|
|
4678
|
-
ohlcvs[candle][i_close] =
|
|
5047
|
+
ohlcvs[candle][i_high] = max(ohlcvs[candle][i_high], price)
|
|
5048
|
+
ohlcvs[candle][i_low] = min(ohlcvs[candle][i_low], price)
|
|
5049
|
+
ohlcvs[candle][i_close] = price
|
|
4679
5050
|
ohlcvs[candle][i_volume] = self.sum(ohlcvs[candle][i_volume], trade['amount'])
|
|
4680
5051
|
ohlcvs[candle][i_count] = self.sum(ohlcvs[candle][i_count], 1)
|
|
4681
5052
|
return ohlcvs
|
|
@@ -4697,6 +5068,9 @@ class Exchange(object):
|
|
|
4697
5068
|
self.cancel_order(id, symbol)
|
|
4698
5069
|
return self.create_order(symbol, type, side, amount, price, params)
|
|
4699
5070
|
|
|
5071
|
+
def edit_order_with_client_order_id(self, clientOrderId: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
|
|
5072
|
+
return self.edit_order('', symbol, type, side, amount, price, self.extend({'clientOrderId': clientOrderId}, params))
|
|
5073
|
+
|
|
4700
5074
|
def edit_order_ws(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
|
|
4701
5075
|
self.cancel_order_ws(id, symbol)
|
|
4702
5076
|
return self.create_order_ws(symbol, type, side, amount, price, params)
|
|
@@ -4779,10 +5153,6 @@ class Exchange(object):
|
|
|
4779
5153
|
})
|
|
4780
5154
|
|
|
4781
5155
|
def safe_market(self, marketId: Str = None, market: Market = None, delimiter: Str = None, marketType: Str = None):
|
|
4782
|
-
result = self.safe_market_structure({
|
|
4783
|
-
'symbol': marketId,
|
|
4784
|
-
'marketId': marketId,
|
|
4785
|
-
})
|
|
4786
5156
|
if marketId is not None:
|
|
4787
5157
|
if (self.markets_by_id is not None) and (marketId in self.markets_by_id):
|
|
4788
5158
|
markets = self.markets_by_id[marketId]
|
|
@@ -4802,20 +5172,22 @@ class Exchange(object):
|
|
|
4802
5172
|
elif delimiter is not None and delimiter != '':
|
|
4803
5173
|
parts = marketId.split(delimiter)
|
|
4804
5174
|
partsLength = len(parts)
|
|
5175
|
+
result = self.safe_market_structure({
|
|
5176
|
+
'symbol': marketId,
|
|
5177
|
+
'marketId': marketId,
|
|
5178
|
+
})
|
|
4805
5179
|
if partsLength == 2:
|
|
4806
5180
|
result['baseId'] = self.safe_string(parts, 0)
|
|
4807
5181
|
result['quoteId'] = self.safe_string(parts, 1)
|
|
4808
5182
|
result['base'] = self.safe_currency_code(result['baseId'])
|
|
4809
5183
|
result['quote'] = self.safe_currency_code(result['quoteId'])
|
|
4810
5184
|
result['symbol'] = result['base'] + '/' + result['quote']
|
|
4811
|
-
|
|
4812
|
-
else:
|
|
4813
|
-
return result
|
|
5185
|
+
return result
|
|
4814
5186
|
if market is not None:
|
|
4815
5187
|
return market
|
|
4816
|
-
return
|
|
5188
|
+
return self.safe_market_structure({'symbol': marketId, 'marketId': marketId})
|
|
4817
5189
|
|
|
4818
|
-
def market_or_null(self, symbol:
|
|
5190
|
+
def market_or_null(self, symbol: Str = None):
|
|
4819
5191
|
if symbol is None:
|
|
4820
5192
|
return None
|
|
4821
5193
|
return self.market(symbol)
|
|
@@ -5111,6 +5483,17 @@ class Exchange(object):
|
|
|
5111
5483
|
def fetch_order(self, id: str, symbol: Str = None, params={}):
|
|
5112
5484
|
raise NotSupported(self.id + ' fetchOrder() is not supported yet')
|
|
5113
5485
|
|
|
5486
|
+
def fetch_order_with_client_order_id(self, clientOrderId: str, symbol: Str = None, params={}):
|
|
5487
|
+
"""
|
|
5488
|
+
create a market order by providing the symbol, side and cost
|
|
5489
|
+
:param str clientOrderId: client order Id
|
|
5490
|
+
:param str symbol: unified symbol of the market to create an order in
|
|
5491
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
5492
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
5493
|
+
"""
|
|
5494
|
+
extendedParams = self.extend(params, {'clientOrderId': clientOrderId})
|
|
5495
|
+
return self.fetch_order('', symbol, extendedParams)
|
|
5496
|
+
|
|
5114
5497
|
def fetch_order_ws(self, id: str, symbol: Str = None, params={}):
|
|
5115
5498
|
raise NotSupported(self.id + ' fetchOrderWs() is not supported yet')
|
|
5116
5499
|
|
|
@@ -5492,9 +5875,34 @@ class Exchange(object):
|
|
|
5492
5875
|
def cancel_order(self, id: str, symbol: Str = None, params={}):
|
|
5493
5876
|
raise NotSupported(self.id + ' cancelOrder() is not supported yet')
|
|
5494
5877
|
|
|
5878
|
+
def cancel_order_with_client_order_id(self, clientOrderId: str, symbol: Str = None, params={}):
|
|
5879
|
+
"""
|
|
5880
|
+
create a market order by providing the symbol, side and cost
|
|
5881
|
+
:param str clientOrderId: client order Id
|
|
5882
|
+
:param str symbol: unified symbol of the market to create an order in
|
|
5883
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
5884
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
5885
|
+
"""
|
|
5886
|
+
extendedParams = self.extend(params, {'clientOrderId': clientOrderId})
|
|
5887
|
+
return self.cancel_order('', symbol, extendedParams)
|
|
5888
|
+
|
|
5495
5889
|
def cancel_order_ws(self, id: str, symbol: Str = None, params={}):
|
|
5496
5890
|
raise NotSupported(self.id + ' cancelOrderWs() is not supported yet')
|
|
5497
5891
|
|
|
5892
|
+
def cancel_orders(self, ids: List[str], symbol: Str = None, params={}):
|
|
5893
|
+
raise NotSupported(self.id + ' cancelOrders() is not supported yet')
|
|
5894
|
+
|
|
5895
|
+
def cancel_orders_with_client_order_ids(self, clientOrderIds: List[str], symbol: Str = None, params={}):
|
|
5896
|
+
"""
|
|
5897
|
+
create a market order by providing the symbol, side and cost
|
|
5898
|
+
:param str[] clientOrderIds: client order Ids
|
|
5899
|
+
:param str symbol: unified symbol of the market to create an order in
|
|
5900
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
5901
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
5902
|
+
"""
|
|
5903
|
+
extendedParams = self.extend(params, {'clientOrderIds': clientOrderIds})
|
|
5904
|
+
return self.cancel_orders([], symbol, extendedParams)
|
|
5905
|
+
|
|
5498
5906
|
def cancel_orders_ws(self, ids: List[str], symbol: Str = None, params={}):
|
|
5499
5907
|
raise NotSupported(self.id + ' cancelOrdersWs() is not supported yet')
|
|
5500
5908
|
|
|
@@ -5510,7 +5918,7 @@ class Exchange(object):
|
|
|
5510
5918
|
def cancel_all_orders_ws(self, symbol: Str = None, params={}):
|
|
5511
5919
|
raise NotSupported(self.id + ' cancelAllOrdersWs() is not supported yet')
|
|
5512
5920
|
|
|
5513
|
-
def cancel_unified_order(self, order, params={}):
|
|
5921
|
+
def cancel_unified_order(self, order: Order, params={}):
|
|
5514
5922
|
return self.cancel_order(self.safe_string(order, 'id'), self.safe_string(order, 'symbol'), params)
|
|
5515
5923
|
|
|
5516
5924
|
def fetch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
@@ -5659,7 +6067,9 @@ class Exchange(object):
|
|
|
5659
6067
|
return self.safe_string(self.commonCurrencies, code, code)
|
|
5660
6068
|
|
|
5661
6069
|
def currency(self, code: str):
|
|
5662
|
-
|
|
6070
|
+
keys = list(self.currencies.keys())
|
|
6071
|
+
numCurrencies = len(keys)
|
|
6072
|
+
if numCurrencies == 0:
|
|
5663
6073
|
raise ExchangeError(self.id + ' currencies not loaded')
|
|
5664
6074
|
if isinstance(code, str):
|
|
5665
6075
|
if code in self.currencies:
|
|
@@ -7067,6 +7477,83 @@ class Exchange(object):
|
|
|
7067
7477
|
"""
|
|
7068
7478
|
raise NotSupported(self.id + ' fetchTransfers() is not supported yet')
|
|
7069
7479
|
|
|
7480
|
+
def un_watch_ohlcv(self, symbol: str, timeframe: str = '1m', params={}):
|
|
7481
|
+
"""
|
|
7482
|
+
watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
7483
|
+
:param str symbol: unified symbol of the market to fetch OHLCV data for
|
|
7484
|
+
:param str timeframe: the length of time each candle represents
|
|
7485
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
7486
|
+
:returns int[][]: A list of candles ordered, open, high, low, close, volume
|
|
7487
|
+
"""
|
|
7488
|
+
raise NotSupported(self.id + ' unWatchOHLCV() is not supported yet')
|
|
7489
|
+
|
|
7490
|
+
def watch_mark_price(self, symbol: str, params={}):
|
|
7491
|
+
"""
|
|
7492
|
+
watches a mark price for a specific market
|
|
7493
|
+
:param str symbol: unified symbol of the market to fetch the ticker for
|
|
7494
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
7495
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
7496
|
+
"""
|
|
7497
|
+
raise NotSupported(self.id + ' watchMarkPrice() is not supported yet')
|
|
7498
|
+
|
|
7499
|
+
def watch_mark_prices(self, symbols: Strings = None, params={}):
|
|
7500
|
+
"""
|
|
7501
|
+
watches the mark price for all markets
|
|
7502
|
+
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
|
7503
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
7504
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
7505
|
+
"""
|
|
7506
|
+
raise NotSupported(self.id + ' watchMarkPrices() is not supported yet')
|
|
7507
|
+
|
|
7508
|
+
def withdraw_ws(self, code: str, amount: float, address: str, tag: Str = None, params={}):
|
|
7509
|
+
"""
|
|
7510
|
+
make a withdrawal
|
|
7511
|
+
:param str code: unified currency code
|
|
7512
|
+
:param float amount: the amount to withdraw
|
|
7513
|
+
:param str address: the address to withdraw to
|
|
7514
|
+
:param str tag:
|
|
7515
|
+
:param dict [params]: extra parameters specific to the bitvavo api endpoint
|
|
7516
|
+
:returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
|
|
7517
|
+
"""
|
|
7518
|
+
raise NotSupported(self.id + ' withdrawWs() is not supported yet')
|
|
7519
|
+
|
|
7520
|
+
def un_watch_my_trades(self, symbol: Str = None, params={}):
|
|
7521
|
+
"""
|
|
7522
|
+
unWatches information on multiple trades made by the user
|
|
7523
|
+
:param str symbol: unified market symbol of the market orders were made in
|
|
7524
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
7525
|
+
:returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
7526
|
+
"""
|
|
7527
|
+
raise NotSupported(self.id + ' unWatchMyTrades() is not supported yet')
|
|
7528
|
+
|
|
7529
|
+
def create_orders_ws(self, orders: List[OrderRequest], params={}):
|
|
7530
|
+
"""
|
|
7531
|
+
create a list of trade orders
|
|
7532
|
+
:param Array orders: list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
|
|
7533
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
7534
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
7535
|
+
"""
|
|
7536
|
+
raise NotSupported(self.id + ' createOrdersWs() is not supported yet')
|
|
7537
|
+
|
|
7538
|
+
def fetch_orders_by_status_ws(self, status: str, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
7539
|
+
"""
|
|
7540
|
+
watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
|
7541
|
+
:param str symbol: unified symbol of the market to fetch the order book for
|
|
7542
|
+
:param int [limit]: the maximum amount of order book entries to return
|
|
7543
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
7544
|
+
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
|
|
7545
|
+
"""
|
|
7546
|
+
raise NotSupported(self.id + ' fetchOrdersByStatusWs() is not supported yet')
|
|
7547
|
+
|
|
7548
|
+
def un_watch_bids_asks(self, symbols: Strings = None, params={}):
|
|
7549
|
+
"""
|
|
7550
|
+
unWatches best bid & ask for symbols
|
|
7551
|
+
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
|
7552
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
7553
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
7554
|
+
"""
|
|
7555
|
+
raise NotSupported(self.id + ' unWatchBidsAsks() is not supported yet')
|
|
7556
|
+
|
|
7070
7557
|
def clean_unsubscription(self, client, subHash: str, unsubHash: str, subHashIsPrefix=False):
|
|
7071
7558
|
if unsubHash in client.subscriptions:
|
|
7072
7559
|
del client.subscriptions[unsubHash]
|
|
@@ -7095,9 +7582,9 @@ class Exchange(object):
|
|
|
7095
7582
|
symbols = self.safe_list(subscription, 'symbols', [])
|
|
7096
7583
|
symbolsLength = len(symbols)
|
|
7097
7584
|
if topic == 'ohlcv':
|
|
7098
|
-
|
|
7099
|
-
for i in range(0, len(
|
|
7100
|
-
symbolAndTimeFrame =
|
|
7585
|
+
symbolsAndTimeframes = self.safe_list(subscription, 'symbolsAndTimeframes', [])
|
|
7586
|
+
for i in range(0, len(symbolsAndTimeframes)):
|
|
7587
|
+
symbolAndTimeFrame = symbolsAndTimeframes[i]
|
|
7101
7588
|
symbol = self.safe_string(symbolAndTimeFrame, 0)
|
|
7102
7589
|
timeframe = self.safe_string(symbolAndTimeFrame, 1)
|
|
7103
7590
|
if (self.ohlcvs is not None) and (symbol in self.ohlcvs):
|
|
@@ -7115,6 +7602,9 @@ class Exchange(object):
|
|
|
7115
7602
|
elif topic == 'ticker':
|
|
7116
7603
|
if symbol in self.tickers:
|
|
7117
7604
|
del self.tickers[symbol]
|
|
7605
|
+
elif topic == 'bidsasks':
|
|
7606
|
+
if symbol in self.bidsasks:
|
|
7607
|
+
del self.bidsasks[symbol]
|
|
7118
7608
|
else:
|
|
7119
7609
|
if topic == 'myTrades' and (self.myTrades is not None):
|
|
7120
7610
|
self.myTrades = None
|
|
@@ -7128,9 +7618,15 @@ class Exchange(object):
|
|
|
7128
7618
|
futures = client.futures
|
|
7129
7619
|
if (futures is not None) and ('fetchPositionsSnapshot' in futures):
|
|
7130
7620
|
del futures['fetchPositionsSnapshot']
|
|
7131
|
-
elif topic == 'ticker' and (self.tickers is not None):
|
|
7621
|
+
elif (topic == 'ticker' or topic == 'markPrice') and (self.tickers is not None):
|
|
7132
7622
|
tickerSymbols = list(self.tickers.keys())
|
|
7133
7623
|
for i in range(0, len(tickerSymbols)):
|
|
7134
7624
|
tickerSymbol = tickerSymbols[i]
|
|
7135
7625
|
if tickerSymbol in self.tickers:
|
|
7136
7626
|
del self.tickers[tickerSymbol]
|
|
7627
|
+
elif topic == 'bidsasks' and (self.bidsasks is not None):
|
|
7628
|
+
bidsaskSymbols = list(self.bidsasks.keys())
|
|
7629
|
+
for i in range(0, len(bidsaskSymbols)):
|
|
7630
|
+
bidsaskSymbol = bidsaskSymbols[i]
|
|
7631
|
+
if bidsaskSymbol in self.bidsasks:
|
|
7632
|
+
del self.bidsasks[bidsaskSymbol]
|