diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 06f83f4df..44288e696 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -408,7 +408,7 @@ class Exchange: else: return DataFrame() - def _get_contract_size(self, pair: str) -> float: + def get_contract_size(self, pair: str) -> float: if self.trading_mode == TradingMode.FUTURES: market = self.markets[pair] contract_size: float = 1.0 @@ -421,7 +421,7 @@ class Exchange: def _trades_contracts_to_amount(self, trades: List) -> List: if len(trades) > 0 and 'symbol' in trades[0]: - contract_size = self._get_contract_size(trades[0]['symbol']) + contract_size = self.get_contract_size(trades[0]['symbol']) if contract_size != 1: for trade in trades: trade['amount'] = trade['amount'] * contract_size @@ -429,7 +429,7 @@ class Exchange: def _order_contracts_to_amount(self, order: Dict) -> Dict: if 'symbol' in order and order['symbol'] is not None: - contract_size = self._get_contract_size(order['symbol']) + contract_size = self.get_contract_size(order['symbol']) if contract_size != 1: for prop in self._ft_has.get('order_props_in_contracts', []): if prop in order and order[prop] is not None: @@ -438,19 +438,13 @@ class Exchange: def _amount_to_contracts(self, pair: str, amount: float) -> float: - contract_size = self._get_contract_size(pair) - if contract_size and contract_size != 1: - return amount / contract_size - else: - return amount + contract_size = self.get_contract_size(pair) + return amount_to_contracts(amount, contract_size) def _contracts_to_amount(self, pair: str, num_contracts: float) -> float: - contract_size = self._get_contract_size(pair) - if contract_size and contract_size != 1: - return num_contracts * contract_size - else: - return num_contracts + contract_size = self.get_contract_size(pair) + return contracts_to_amount(num_contracts, contract_size) def set_sandbox(self, api: ccxt.Exchange, exchange_config: dict, name: str) -> None: if exchange_config.get('sandbox'): @@ -2898,6 +2892,33 @@ def market_is_active(market: Dict) -> bool: return market.get('active', True) is not False +def amount_to_contracts(amount: float, contract_size: float) -> float: + """ + Convert amount to contracts. + :param amount: amount to convert + :param contract_size: contract size - taken from exchange.get_contract_size(pair) + :return: num-contracts + """ + if contract_size and contract_size != 1: + return amount / contract_size + else: + return amount + + +def contracts_to_amount(num_contracts: float, contract_size: float) -> float: + """ + Takes num-contracts and converts it to contract size + :param num_contracts: number of contracts + :param contract_size: contract size - taken from exchange.get_contract_size(pair) + :return: Amount + """ + + if contract_size and contract_size != 1: + return num_contracts * contract_size + else: + return num_contracts + + def amount_to_precision(amount: float, amount_precision: Optional[float], precisionMode: Optional[int]) -> float: """ diff --git a/tests/exchange/test_ccxt_compat.py b/tests/exchange/test_ccxt_compat.py index c3a5fe17f..29b317c3c 100644 --- a/tests/exchange/test_ccxt_compat.py +++ b/tests/exchange/test_ccxt_compat.py @@ -409,14 +409,14 @@ class TestCCXTExchange(): assert (isinstance(futures_leverage, float) or isinstance(futures_leverage, int)) assert futures_leverage >= 1.0 - def test_ccxt__get_contract_size(self, exchange_futures): + def test_ccxt_get_contract_size(self, exchange_futures): futures, futures_name = exchange_futures if futures: futures_pair = EXCHANGES[futures_name].get( 'futures_pair', EXCHANGES[futures_name]['pair'] ) - contract_size = futures._get_contract_size(futures_pair) + contract_size = futures.get_contract_size(futures_pair) assert (isinstance(contract_size, float) or isinstance(contract_size, int)) assert contract_size >= 0.0 diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 7e61f76cd..5002a33e1 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -4288,7 +4288,7 @@ def test__fetch_and_calculate_funding_fees_datetime_called( ('XLTCUSDT', 0.01, 'futures'), ('ETH/USDT:USDT', 10, 'futures') ]) -def test__get_contract_size(mocker, default_conf, pair, expected_size, trading_mode): +def est__get_contract_size(mocker, default_conf, pair, expected_size, trading_mode): api_mock = MagicMock() default_conf['trading_mode'] = trading_mode default_conf['margin_mode'] = 'isolated' @@ -4307,7 +4307,7 @@ def test__get_contract_size(mocker, default_conf, pair, expected_size, trading_m 'contractSize': '10', } }) - size = exchange._get_contract_size(pair) + size = exchange.get_contract_size(pair) assert expected_size == size @@ -5146,7 +5146,7 @@ def test_stoploss_contract_size(mocker, default_conf, contract_size, order_amoun mocker.patch('freqtrade.exchange.Exchange.price_to_precision', lambda s, x, y: y) exchange = get_patched_exchange(mocker, default_conf, api_mock) - exchange._get_contract_size = MagicMock(return_value=contract_size) + exchange.get_contract_size = MagicMock(return_value=contract_size) api_mock.create_order.reset_mock() order = exchange.stoploss(