diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index d37effefb..58321a2db 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -376,7 +376,7 @@ class Exchange: if self.trading_mode == TradingMode.FUTURES: market = self.markets[pair] contract_size: float = 1.0 - if 'contractSize' in market and market['contractSize'] is not None: + if market['contractSize'] is not None: # ccxt has contractSize in markets as string contract_size = float(market['contractSize']) return contract_size @@ -685,13 +685,9 @@ class Exchange: except KeyError: raise ValueError(f"Can't get market information for symbol {pair}") - if 'limits' not in market: - return None - min_stake_amounts = [] limits = market['limits'] - if ('cost' in limits and 'min' in limits['cost'] - and limits['cost']['min'] is not None): + if (limits['cost']['min'] is not None): min_stake_amounts.append( self._contracts_to_amount( pair, @@ -699,8 +695,7 @@ class Exchange: ) ) - if ('amount' in limits and 'min' in limits['amount'] - and limits['amount']['min'] is not None): + if (limits['amount']['min'] is not None): min_stake_amounts.append( self._contracts_to_amount( pair, @@ -1819,12 +1814,7 @@ class Exchange: :param nominal_value: The total value of the trade in quote currency (collateral + debt) """ market = self.markets[pair] - if ( - 'limits' in market and - 'leverage' in market['limits'] and - 'max' in market['limits']['leverage'] and - market['limits']['leverage']['max'] is not None - ): + if market['limits']['leverage']['max'] is not None: return market['limits']['leverage']['max'] else: return 1.0 diff --git a/freqtrade/plugins/pairlist/PriceFilter.py b/freqtrade/plugins/pairlist/PriceFilter.py index 63623d8c8..009789eaf 100644 --- a/freqtrade/plugins/pairlist/PriceFilter.py +++ b/freqtrade/plugins/pairlist/PriceFilter.py @@ -90,8 +90,7 @@ class PriceFilter(IPairList): price = ticker['last'] market = self._exchange.markets[pair] limits = market['limits'] - if ('amount' in limits and 'min' in limits['amount'] - and limits['amount']['min'] is not None): + if (limits['amount']['min'] is not None): min_amount = limits['amount']['min'] min_precision = market['precision']['amount'] diff --git a/tests/conftest.py b/tests/conftest.py index 1d8826f01..207f6ae24 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -583,12 +583,16 @@ def get_markets(): 'cost': 8, }, 'lot': 0.00000001, + 'contractSize': None, 'limits': { 'amount': { 'min': 0.01, 'max': 1000, }, - 'price': 500000, + 'price': { + 'min': None, + 'max': 500000, + }, 'cost': { 'min': 0.0001, 'max': 500000, @@ -614,12 +618,16 @@ def get_markets(): 'cost': 8, }, 'lot': 0.00000001, + 'contractSize': None, 'limits': { 'amount': { 'min': 0.01, 'max': 1000, }, - 'price': 500000, + 'price': { + 'min': None, + 'max': 500000, + }, 'cost': { 'min': 0.0001, 'max': 500000, @@ -644,12 +652,16 @@ def get_markets(): 'cost': 8, }, 'lot': 0.00000001, + 'contractSize': None, 'limits': { 'amount': { 'min': 0.01, 'max': 1000, }, - 'price': 500000, + 'price': { + 'min': None, + 'max': 500000, + }, 'cost': { 'min': 0.0001, 'max': 500000, @@ -674,12 +686,16 @@ def get_markets(): 'cost': 8, }, 'lot': 0.00000001, + 'contractSize': None, 'limits': { 'amount': { 'min': 0.01, 'max': 1000, }, - 'price': 500000, + 'price': { + 'min': None, + 'max': 500000, + }, 'cost': { 'min': 0.0001, 'max': 500000, @@ -705,16 +721,24 @@ def get_markets(): 'cost': 8, }, 'lot': 0.00000001, + 'contractSize': None, 'limits': { 'amount': { 'min': 0.01, 'max': 1000, }, - 'price': 500000, + 'price': { + 'min': None, + 'max': 500000, + }, 'cost': { 'min': 0.0001, 'max': 500000, }, + 'leverage': { + 'min': None, + 'max': None, + }, }, 'info': {}, }, @@ -732,16 +756,24 @@ def get_markets(): 'cost': 8, }, 'lot': 0.00000001, + 'contractSize': None, 'limits': { 'amount': { 'min': 0.01, 'max': 1000, }, - 'price': 500000, + 'price': { + 'min': None, + 'max': 500000, + }, 'cost': { 'min': 0.0001, 'max': 500000, }, + 'leverage': { + 'min': None, + 'max': None, + }, }, 'info': {}, }, @@ -753,6 +785,7 @@ def get_markets(): 'active': False, 'spot': True, 'type': 'spot', + 'contractSize': None, 'precision': { 'base': 8, 'quote': 8, @@ -771,7 +804,11 @@ def get_markets(): 'cost': { 'min': 0.0001, 'max': None - } + }, + 'leverage': { + 'min': None, + 'max': None, + }, }, 'info': {}, }, @@ -785,6 +822,7 @@ def get_markets(): 'swap': True, 'margin': True, 'type': 'spot', + 'contractSize': None, 'precision': { 'amount': 8, 'price': 8 @@ -797,7 +835,15 @@ def get_markets(): 'price': { 'min': 1e-08, 'max': None - } + }, + 'leverage': { + 'min': None, + 'max': None, + }, + 'cost': { + 'min': None, + 'max': None, + }, }, 'active': True, 'info': {}, @@ -813,6 +859,7 @@ def get_markets(): 'swap': True, 'margin': True, 'type': 'spot', + 'contractSize': None, 'precision': { 'amount': 8, 'price': 8 @@ -825,7 +872,15 @@ def get_markets(): 'price': { 'min': 1e-08, 'max': None - } + }, + 'leverage': { + 'min': None, + 'max': None, + }, + 'cost': { + 'min': None, + 'max': None, + }, }, 'info': {}, }, @@ -843,12 +898,16 @@ def get_markets(): 'cost': 8, }, 'lot': 0.00000001, + 'contractSize': None, 'limits': { 'amount': { 'min': 0.01, 'max': 1000, }, - 'price': 500000, + 'price': { + 'min': None, + 'max': 500000, + }, 'cost': { 'min': 0.0001, 'max': 500000, @@ -870,12 +929,16 @@ def get_markets(): 'cost': 8, }, 'lot': 0.00000001, + 'contractSize': None, 'limits': { 'amount': { 'min': 0.01, 'max': 1000, }, - 'price': 500000, + 'price': { + 'min': None, + 'max': 500000, + }, 'cost': { 'min': 0.0001, 'max': 500000, @@ -891,6 +954,7 @@ def get_markets(): 'active': True, 'spot': True, 'type': 'spot', + 'contractSize': None, 'precision': { 'price': 8, 'amount': 8, @@ -902,11 +966,18 @@ def get_markets(): 'min': 0.01, 'max': 1000, }, - 'price': 500000, + 'price': { + 'min': None, + 'max': 500000 + }, 'cost': { 'min': 0.0001, 'max': 500000, }, + 'leverage': { + 'min': None, + 'max': None, + }, }, 'info': {}, }, @@ -931,7 +1002,15 @@ def get_markets(): 'price': { 'min': 1e-08, 'max': None - } + }, + 'leverage': { + 'min': None, + 'max': None, + }, + 'cost': { + 'min': None, + 'max': None, + }, }, 'info': {}, }, @@ -943,12 +1022,16 @@ def get_markets(): 'active': True, 'spot': False, 'type': 'swap', - 'contractSize': '0.01', + 'contractSize': 0.01, 'precision': { 'amount': 8, 'price': 8 }, 'limits': { + 'leverage': { + 'min': None, + 'max': None, + }, 'amount': { 'min': 0.06646786, 'max': None @@ -956,7 +1039,11 @@ def get_markets(): 'price': { 'min': 1e-08, 'max': None - } + }, + 'cost': { + 'min': None, + 'max': None, + }, }, 'info': {}, }, @@ -968,6 +1055,7 @@ def get_markets(): 'active': True, 'spot': True, 'type': 'spot', + 'contractSize': None, 'precision': { 'base': 8, 'quote': 8, @@ -975,6 +1063,10 @@ def get_markets(): 'price': 5 }, 'limits': { + 'leverage': { + 'min': None, + 'max': None, + }, 'amount': { 'min': 0.001, 'max': 10000000.0 @@ -1137,6 +1229,22 @@ def shitcoinmarkets(markets_static): "price": 4 }, "limits": { + 'leverage': { + 'min': None, + 'max': None, + }, + 'amount': { + 'min': None, + 'max': None, + }, + 'price': { + 'min': None, + 'max': None, + }, + 'cost': { + 'min': None, + 'max': None, + }, }, "id": "NANOUSDT", "symbol": "NANO/USDT", @@ -1162,6 +1270,22 @@ def shitcoinmarkets(markets_static): "price": 4 }, "limits": { + 'leverage': { + 'min': None, + 'max': None, + }, + 'amount': { + 'min': None, + 'max': None, + }, + 'price': { + 'min': None, + 'max': None, + }, + 'cost': { + 'min': None, + 'max': None, + }, }, "id": "ADAHALFUSDT", "symbol": "ADAHALF/USDT", @@ -1187,6 +1311,22 @@ def shitcoinmarkets(markets_static): "price": 4 }, "limits": { + 'leverage': { + 'min': None, + 'max': None, + }, + 'amount': { + 'min': None, + 'max': None, + }, + 'price': { + 'min': None, + 'max': None, + }, + 'cost': { + 'min': None, + 'max': None, + }, }, "id": "ADADOUBLEUSDT", "symbol": "ADADOUBLE/USDT", diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 750b806cf..5836aa4e4 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -356,23 +356,10 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None: with pytest.raises(ValueError, match=r'.*get market information.*'): exchange.get_min_pair_stake_amount('BNB/BTC', 1, stoploss) - # no 'limits' section - result = exchange.get_min_pair_stake_amount('ETH/BTC', 1, stoploss) - assert result is None - - # empty 'limits' section - markets["ETH/BTC"]["limits"] = {} - mocker.patch( - 'freqtrade.exchange.Exchange.markets', - PropertyMock(return_value=markets) - ) - result = exchange.get_min_pair_stake_amount('ETH/BTC', 1, stoploss) - assert result is None - # no cost Min markets["ETH/BTC"]["limits"] = { - 'cost': {"min": None}, - 'amount': {} + 'cost': {'min': None, 'max': None}, + 'amount': {'min': None, 'max': None}, } mocker.patch( 'freqtrade.exchange.Exchange.markets', @@ -383,8 +370,8 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None: # no amount Min markets["ETH/BTC"]["limits"] = { - 'cost': {}, - 'amount': {"min": None} + 'cost': {'min': None, 'max': None}, + 'amount': {'min': None, 'max': None}, } mocker.patch( 'freqtrade.exchange.Exchange.markets', @@ -395,8 +382,8 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None: # empty 'cost'/'amount' section markets["ETH/BTC"]["limits"] = { - 'cost': {}, - 'amount': {} + 'cost': {'min': None, 'max': None}, + 'amount': {'min': None, 'max': None}, } mocker.patch( 'freqtrade.exchange.Exchange.markets', @@ -407,8 +394,8 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None: # min cost is set markets["ETH/BTC"]["limits"] = { - 'cost': {'min': 2}, - 'amount': {} + 'cost': {'min': 2, 'max': None}, + 'amount': {'min': None, 'max': None}, } mocker.patch( 'freqtrade.exchange.Exchange.markets', @@ -423,8 +410,8 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None: # min amount is set markets["ETH/BTC"]["limits"] = { - 'cost': {}, - 'amount': {'min': 2} + 'cost': {'min': None, 'max': None}, + 'amount': {'min': 2, 'max': None}, } mocker.patch( 'freqtrade.exchange.Exchange.markets', @@ -439,8 +426,8 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None: # min amount and cost are set (cost is minimal) markets["ETH/BTC"]["limits"] = { - 'cost': {'min': 2}, - 'amount': {'min': 2} + 'cost': {'min': 2, 'max': None}, + 'amount': {'min': 2, 'max': None}, } mocker.patch( 'freqtrade.exchange.Exchange.markets', @@ -455,8 +442,8 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None: # min amount and cost are set (amount is minial) markets["ETH/BTC"]["limits"] = { - 'cost': {'min': 8}, - 'amount': {'min': 2} + 'cost': {'min': 8, 'max': None}, + 'amount': {'min': 2, 'max': None}, } mocker.patch( 'freqtrade.exchange.Exchange.markets', @@ -3557,11 +3544,11 @@ def test_calculate_funding_fees( funding_rates = DataFrame([ {'date': prior_date, 'open': funding_rate}, # Line not used. {'date': trade_date, 'open': funding_rate}, - ]) + ]) mark_rates = DataFrame([ {'date': prior_date, 'open': mark_price}, {'date': trade_date, 'open': mark_price}, - ]) + ]) df = exchange.combine_funding_and_mark(funding_rates, mark_rates) assert exchange.calculate_funding_fees(