Simplify usage of amount_to_contract precision

This commit is contained in:
Matthias 2022-08-25 07:08:22 +02:00
parent 9e48e6a40b
commit 6636f17e0f
5 changed files with 41 additions and 28 deletions

View File

@ -9,11 +9,11 @@ from freqtrade.exchange.bitpanda import Bitpanda
from freqtrade.exchange.bittrex import Bittrex from freqtrade.exchange.bittrex import Bittrex
from freqtrade.exchange.bybit import Bybit from freqtrade.exchange.bybit import Bybit
from freqtrade.exchange.coinbasepro import Coinbasepro from freqtrade.exchange.coinbasepro import Coinbasepro
from freqtrade.exchange.exchange import (amount_to_contracts, amount_to_precision, from freqtrade.exchange.exchange import (amount_to_contract_precision, amount_to_contracts,
available_exchanges, ccxt_exchanges, contracts_to_amount, amount_to_precision, available_exchanges, ccxt_exchanges,
date_minus_candles, is_exchange_known_ccxt, contracts_to_amount, date_minus_candles,
is_exchange_officially_supported, market_is_active, is_exchange_known_ccxt, is_exchange_officially_supported,
price_to_precision, timeframe_to_minutes, market_is_active, price_to_precision, timeframe_to_minutes,
timeframe_to_msecs, timeframe_to_next_date, timeframe_to_msecs, timeframe_to_next_date,
timeframe_to_prev_date, timeframe_to_seconds, timeframe_to_prev_date, timeframe_to_seconds,
validate_exchange, validate_exchanges) validate_exchange, validate_exchanges)

View File

@ -2943,6 +2943,29 @@ def amount_to_precision(amount: float, amount_precision: Optional[float],
return amount return amount
def amount_to_contract_precision(
amount, amount_precision: Optional[float], precisionMode: Optional[int],
contract_size: Optional[float]) -> float:
"""
Returns the amount to buy or sell to a precision the Exchange accepts
including calculation to and from contracts.
Re-implementation of ccxt internal methods - ensuring we can test the result is correct
based on our definitions.
:param amount: amount to truncate
:param amount_precision: amount precision to use.
should be retrieved from markets[pair]['precision']['amount']
:param precisionMode: precision mode to use. Should be used from precisionMode
one of ccxt's DECIMAL_PLACES, SIGNIFICANT_DIGITS, or TICK_SIZE
:param contract_size: contract size - taken from exchange.get_contract_size(pair)
:return: truncated amount
"""
if amount_precision is not None and precisionMode is not None:
contracts = amount_to_contracts(amount, contract_size)
amount_p = amount_to_precision(contracts, amount_precision, precisionMode)
return contracts_to_amount(amount_p, contract_size)
return amount
def price_to_precision(price: float, price_precision: Optional[float], def price_to_precision(price: float, price_precision: Optional[float],
precisionMode: Optional[int]) -> float: precisionMode: Optional[int]) -> float:
""" """

View File

@ -23,9 +23,8 @@ from freqtrade.data.dataprovider import DataProvider
from freqtrade.enums import (BacktestState, CandleType, ExitCheckTuple, ExitType, RunMode, from freqtrade.enums import (BacktestState, CandleType, ExitCheckTuple, ExitType, RunMode,
TradingMode) TradingMode)
from freqtrade.exceptions import DependencyException, OperationalException from freqtrade.exceptions import DependencyException, OperationalException
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds from freqtrade.exchange import (amount_to_contract_precision, price_to_precision,
from freqtrade.exchange.exchange import (amount_to_contracts, amount_to_precision, timeframe_to_minutes, timeframe_to_seconds)
contracts_to_amount, price_to_precision)
from freqtrade.mixins import LoggingMixin from freqtrade.mixins import LoggingMixin
from freqtrade.optimize.backtest_caching import get_strategy_run_id from freqtrade.optimize.backtest_caching import get_strategy_run_id
from freqtrade.optimize.bt_progress import BTProgress from freqtrade.optimize.bt_progress import BTProgress
@ -659,11 +658,8 @@ class Backtesting:
exit_candle_time = sell_row[DATE_IDX].to_pydatetime() exit_candle_time = sell_row[DATE_IDX].to_pydatetime()
order_type = self.strategy.order_types['exit'] order_type = self.strategy.order_types['exit']
# amount = amount or trade.amount # amount = amount or trade.amount
amount = contracts_to_amount( amount = amount_to_contract_precision(amount or trade.amount, trade.amount_precision,
amount_to_precision( self.precision_mode, trade.contract_size)
amount_to_contracts(amount or trade.amount, trade.contract_size),
trade.amount_precision, self.precision_mode),
trade.contract_size)
rate = price_to_precision(close_rate, trade.price_precision, self.precision_mode) rate = price_to_precision(close_rate, trade.price_precision, self.precision_mode)
order = Order( order = Order(
id=self.order_id_counter, id=self.order_id_counter,
@ -835,11 +831,8 @@ class Backtesting:
contract_size = self.exchange.get_contract_size(pair) contract_size = self.exchange.get_contract_size(pair)
precision_amount = self.exchange.get_precision_amount(pair) precision_amount = self.exchange.get_precision_amount(pair)
amount = contracts_to_amount( amount = amount_to_contract_precision(amount_p, precision_amount, self.precision_mode,
amount_to_precision( contract_size)
amount_to_contracts(amount_p, contract_size),
precision_amount, self.precision_mode),
contract_size)
# Backcalculate actual stake amount. # Backcalculate actual stake amount.
stake_amount = amount * propose_rate / leverage stake_amount = amount * propose_rate / leverage

View File

@ -14,8 +14,7 @@ from freqtrade.constants import (DATETIME_PRINT_FORMAT, MATH_CLOSE_PREC, NON_OPE
BuySell, LongShort) BuySell, LongShort)
from freqtrade.enums import ExitType, TradingMode from freqtrade.enums import ExitType, TradingMode
from freqtrade.exceptions import DependencyException, OperationalException from freqtrade.exceptions import DependencyException, OperationalException
from freqtrade.exchange import amount_to_precision, price_to_precision from freqtrade.exchange import amount_to_contract_precision, price_to_precision
from freqtrade.exchange.exchange import amount_to_contracts, contracts_to_amount
from freqtrade.leverage import interest from freqtrade.leverage import interest
from freqtrade.persistence.base import _DECL_BASE from freqtrade.persistence.base import _DECL_BASE
from freqtrade.util import FtPrecise from freqtrade.util import FtPrecise
@ -625,11 +624,8 @@ class LocalTrade():
else: else:
logger.warning( logger.warning(
f'Got different open_order_id {self.open_order_id} != {order.order_id}') f'Got different open_order_id {self.open_order_id} != {order.order_id}')
amount_tr = contracts_to_amount( amount_tr = amount_to_contract_precision(self.amount, self.amount_precision,
amount_to_precision( self.precision_mode, self.contract_size)
amount_to_contracts(self.amount, self.contract_size),
self.amount_precision, self.precision_mode),
self.contract_size)
if isclose(order.safe_amount_after_fee, amount_tr, abs_tol=MATH_CLOSE_PREC): if isclose(order.safe_amount_after_fee, amount_tr, abs_tol=MATH_CLOSE_PREC):
self.close(order.safe_price) self.close(order.safe_price)
else: else:
@ -882,8 +878,8 @@ class LocalTrade():
self.realized_profit = close_profit_abs self.realized_profit = close_profit_abs
self.close_profit_abs = profit self.close_profit_abs = profit
current_amount_tr = amount_to_precision(float(current_amount), current_amount_tr = amount_to_contract_precision(
self.amount_precision, self.precision_mode) float(current_amount), self.amount_precision, self.precision_mode, self.contract_size)
if current_amount_tr > 0.0: if current_amount_tr > 0.0:
# Trade is still open # Trade is still open
# Leverage not updated, as we don't allow changing leverage through DCA at the moment. # Leverage not updated, as we don't allow changing leverage through DCA at the moment.

View File

@ -18,7 +18,8 @@ from tests.conftest import patch_exchange
def test_backtest_position_adjustment(default_conf, fee, mocker, testdatadir) -> None: def test_backtest_position_adjustment(default_conf, fee, mocker, testdatadir) -> None:
default_conf['use_exit_signal'] = False default_conf['use_exit_signal'] = False
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
mocker.patch('freqtrade.optimize.backtesting.amount_to_precision', lambda x, y, z: round(x, 8)) mocker.patch('freqtrade.optimize.backtesting.amount_to_contract_precision',
lambda x, *args, **kwargs: round(x, 8))
mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001) mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001)
mocker.patch("freqtrade.exchange.Exchange.get_max_pair_stake_amount", return_value=float('inf')) mocker.patch("freqtrade.exchange.Exchange.get_max_pair_stake_amount", return_value=float('inf'))
patch_exchange(mocker) patch_exchange(mocker)