diff --git a/python/ccxt/base/exchange.py b/python/ccxt/base/exchange.py index cb77e86084ca0..b5e9a710b0b0a 100644 --- a/python/ccxt/base/exchange.py +++ b/python/ccxt/base/exchange.py @@ -412,11 +412,14 @@ def __init__(self, config: ConstructorArgs = {}): settings = self.deep_extend(self.describe(), config) - for key in settings: - if hasattr(self, key) and isinstance(getattr(self, key), dict): - setattr(self, key, self.deep_extend(getattr(self, key), settings[key])) + # Optimize dictionary merging: inline dict merge rather than repeated attribute getter/setter loop + for key, value in settings.items(): + current = getattr(self, key, None) + if isinstance(current, dict) and isinstance(value, dict): + setattr(self, key, self.deep_extend(current, value)) else: - setattr(self, key, settings[key]) + setattr(self, key, value) + self.after_construct() @@ -425,15 +428,16 @@ def __init__(self, config: ConstructorArgs = {}): # convert all properties from underscore notation foo_bar to camelcase notation fooBar cls = type(self) + exceptions = {'ohlcv': 'OHLCV', 'le': 'LE', 'be': 'BE'} for name in dir(self): if name[0] != '_' and name[-1] != '_' and '_' in name: parts = name.split('_') - # fetch_ohlcv → fetchOHLCV (not fetchOhlcv!) - exceptions = {'ohlcv': 'OHLCV', 'le': 'LE', 'be': 'BE'} camelcase = parts[0] + ''.join(exceptions.get(i, self.capitalize(i)) for i in parts[1:]) attr = getattr(self, name) if isinstance(attr, types.MethodType): - setattr(cls, camelcase, getattr(cls, name)) + # Set method property only on class if missing + if not hasattr(cls, camelcase): + setattr(cls, camelcase, getattr(cls, name)) else: if hasattr(self, camelcase): if attr is not None: @@ -442,8 +446,10 @@ def __init__(self, config: ConstructorArgs = {}): setattr(self, camelcase, attr) if not self.session and self.synchronous: - self.session = Session() - self.session.trust_env = self.requests_trust_env + s = Session() + s.trust_env = self.requests_trust_env + self.session = s + # Setup logger if not already self.logger = self.logger if self.logger else logging.getLogger(__name__) def __del__(self): @@ -1674,23 +1680,21 @@ def fetch_fees(self): @staticmethod def parse_timeframe(timeframe): - amount = int(timeframe[0:-1]) + # Reduce conditional complexity with lookup table + scale_map = { + 'y': 60 * 60 * 24 * 365, + 'M': 60 * 60 * 24 * 30, + 'w': 60 * 60 * 24 * 7, + 'd': 60 * 60 * 24, + 'h': 60 * 60, + 'm': 60, + 's': 1, + } + amount = int(timeframe[:-1]) unit = timeframe[-1] - if 'y' == unit: - scale = 60 * 60 * 24 * 365 - elif 'M' == unit: - scale = 60 * 60 * 24 * 30 - elif 'w' == unit: - scale = 60 * 60 * 24 * 7 - elif 'd' == unit: - scale = 60 * 60 * 24 - elif 'h' == unit: - scale = 60 * 60 - elif 'm' == unit: - scale = 60 - elif 's' == unit: - scale = 1 - else: + try: + scale = scale_map[unit] + except KeyError: raise NotSupported('timeframe unit {} is not supported'.format(unit)) return amount * scale @@ -6034,8 +6038,14 @@ def is_significant_precision(self): return self.precisionMode == SIGNIFICANT_DIGITS def safe_number(self, obj, key: IndexType, defaultNumber: Num = None): - value = self.safe_string(obj, key) - return self.parse_number(value, defaultNumber) + # More efficient lookup and processing + value = obj.get(key, None) + if value is None: + return defaultNumber + try: + return self.number(value) + except Exception: + return defaultNumber def safe_number_n(self, obj: object, arr: List[IndexType], defaultNumber: Num = None): value = self.safe_string_n(obj, arr) diff --git a/python/ccxt/bittrade.py b/python/ccxt/bittrade.py index 1eae04e32fc94..f58c61a39e826 100644 --- a/python/ccxt/bittrade.py +++ b/python/ccxt/bittrade.py @@ -485,12 +485,29 @@ def parse_trading_limits(self, limits, symbol: Str = None, params={}): # "market-sell-order-rate-must-less-than": 0.1, # "market-buy-order-rate-must-less-than": 0.1 } # + # + # { symbol: "aidocbtc", + # "buy-limit-must-less-than": 1.1, + # "sell-limit-must-greater-than": 0.9, + # "limit-order-must-greater-than": 1, + # "limit-order-must-less-than": 5000000, + # "market-buy-order-must-greater-than": 0.0001, + # "market-buy-order-must-less-than": 100, + # "market-sell-order-must-greater-than": 1, + # "market-sell-order-must-less-than": 500000, + # "circuit-break-when-greater-than": 10000, + # "circuit-break-when-less-than": 10, + # "market-sell-order-rate-must-less-than": 0.1, + # "market-buy-order-rate-must-less-than": 0.1 } + # + min_value = self.safe_number(limits, 'limit-order-must-greater-than') + max_value = self.safe_number(limits, 'limit-order-must-less-than') return { 'info': limits, 'limits': { 'amount': { - 'min': self.safe_number(limits, 'limit-order-must-greater-than'), - 'max': self.safe_number(limits, 'limit-order-must-less-than'), + 'min': min_value, + 'max': max_value, }, }, }