diff --git a/freqtrade/commands/optimize_commands.py b/freqtrade/commands/optimize_commands.py index 2238c5e0a..e8f896d0b 100644 --- a/freqtrade/commands/optimize_commands.py +++ b/freqtrade/commands/optimize_commands.py @@ -5,7 +5,7 @@ from freqtrade import constants from freqtrade.configuration import setup_utils_configuration from freqtrade.enums import RunMode from freqtrade.exceptions import OperationalException -from freqtrade.misc import round_coin_value +from freqtrade.util import round_coin_value logger = logging.getLogger(__name__) diff --git a/freqtrade/misc.py b/freqtrade/misc.py index 5b04d815b..a6c6f15fd 100644 --- a/freqtrade/misc.py +++ b/freqtrade/misc.py @@ -11,54 +11,12 @@ from urllib.parse import urlparse import pandas as pd import rapidjson -from freqtrade.constants import DECIMAL_PER_COIN_FALLBACK, DECIMALS_PER_COIN from freqtrade.enums import SignalTagType, SignalType logger = logging.getLogger(__name__) -def decimals_per_coin(coin: str): - """ - Helper method getting decimal amount for this coin - example usage: f".{decimals_per_coin('USD')}f" - :param coin: Which coin are we printing the price / value for - """ - return DECIMALS_PER_COIN.get(coin, DECIMAL_PER_COIN_FALLBACK) - - -def round_value(value: float, decimals: int, keep_trailing_zeros=False) -> str: - """ - Round value to given decimals - :param value: Value to be rounded - :param decimals: Number of decimals to round to - :param keep_trailing_zeros: Keep trailing zeros "222.200" vs. "222.2" - :return: Rounded value as string - """ - val = f"{value:.{decimals}f}" - if not keep_trailing_zeros: - val = val.rstrip('0').rstrip('.') - return val - - -def round_coin_value( - value: float, coin: str, show_coin_name=True, keep_trailing_zeros=False) -> str: - """ - Get price value for this coin - :param value: Value to be printed - :param coin: Which coin are we printing the price / value for - :param show_coin_name: Return string in format: "222.22 USDT" or "222.22" - :param keep_trailing_zeros: Keep trailing zeros "222.200" vs. "222.2" - :return: Formatted / rounded value (with or without coin name) - """ - val = f"{value:.{decimals_per_coin(coin)}f}" - val = round_value(value, decimals_per_coin(coin), keep_trailing_zeros) - if show_coin_name: - val = f"{val} {coin}" - - return val - - def file_dump_json(filename: Path, data: Any, is_zip: bool = False, log: bool = True) -> None: """ Dump JSON data into a file diff --git a/freqtrade/optimize/hyperopt_tools.py b/freqtrade/optimize/hyperopt_tools.py index ee03aae1a..ecb7d598e 100644 --- a/freqtrade/optimize/hyperopt_tools.py +++ b/freqtrade/optimize/hyperopt_tools.py @@ -14,9 +14,10 @@ from pandas import isna, json_normalize from freqtrade.constants import FTHYPT_FILEVERSION, Config from freqtrade.enums import HyperoptState from freqtrade.exceptions import OperationalException -from freqtrade.misc import deep_merge_dicts, round_coin_value, round_dict, safe_value_fallback2 +from freqtrade.misc import deep_merge_dicts, round_dict, safe_value_fallback2 from freqtrade.optimize.hyperopt_epoch_filters import hyperopt_filter_epochs from freqtrade.optimize.optimize_reports import generate_wins_draws_losses +from freqtrade.util import round_coin_value logger = logging.getLogger(__name__) diff --git a/freqtrade/optimize/optimize_reports/bt_output.py b/freqtrade/optimize/optimize_reports/bt_output.py index 5987f2a61..fc56e0362 100644 --- a/freqtrade/optimize/optimize_reports/bt_output.py +++ b/freqtrade/optimize/optimize_reports/bt_output.py @@ -4,9 +4,9 @@ from typing import Any, Dict, List from tabulate import tabulate from freqtrade.constants import UNLIMITED_STAKE_AMOUNT, Config -from freqtrade.misc import decimals_per_coin, round_coin_value from freqtrade.optimize.optimize_reports.optimize_reports import generate_periodic_breakdown_stats from freqtrade.types import BacktestResultType +from freqtrade.util import decimals_per_coin, round_coin_value logger = logging.getLogger(__name__) diff --git a/freqtrade/optimize/optimize_reports/optimize_reports.py b/freqtrade/optimize/optimize_reports/optimize_reports.py index cb75a1a32..e925bce86 100644 --- a/freqtrade/optimize/optimize_reports/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports/optimize_reports.py @@ -10,8 +10,8 @@ from freqtrade.constants import BACKTEST_BREAKDOWNS, DATETIME_PRINT_FORMAT, IntO from freqtrade.data.metrics import (calculate_cagr, calculate_calmar, calculate_csum, calculate_expectancy, calculate_market_change, calculate_max_drawdown, calculate_sharpe, calculate_sortino) -from freqtrade.misc import decimals_per_coin, round_coin_value from freqtrade.types import BacktestResultType +from freqtrade.util import decimals_per_coin, round_coin_value logger = logging.getLogger(__name__) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 809c63e78..6decd7f7b 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -25,13 +25,13 @@ from freqtrade.exceptions import ExchangeError, PricingError from freqtrade.exchange import timeframe_to_minutes, timeframe_to_msecs from freqtrade.exchange.types import Tickers from freqtrade.loggers import bufferHandler -from freqtrade.misc import decimals_per_coin from freqtrade.persistence import KeyStoreKeys, KeyValueStore, PairLocks, Trade from freqtrade.persistence.models import PairLock from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist from freqtrade.rpc.fiat_convert import CryptoToFiatConverter from freqtrade.rpc.rpc_types import RPCSendMsg -from freqtrade.util import dt_humanize, dt_now, dt_ts_def, format_date, shorten_date +from freqtrade.util import (decimals_per_coin, dt_humanize, dt_now, dt_ts_def, format_date, + shorten_date) from freqtrade.wallets import PositionWallet, Wallet diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 782898c57..63785b1ef 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -29,11 +29,11 @@ from freqtrade.__init__ import __version__ from freqtrade.constants import DUST_PER_COIN, Config from freqtrade.enums import MarketDirection, RPCMessageType, SignalDirection, TradingMode from freqtrade.exceptions import OperationalException -from freqtrade.misc import chunks, plural, round_coin_value +from freqtrade.misc import chunks, plural from freqtrade.persistence import Trade from freqtrade.rpc import RPC, RPCException, RPCHandler from freqtrade.rpc.rpc_types import RPCSendMsg -from freqtrade.util import dt_humanize +from freqtrade.util import dt_humanize, round_coin_value MAX_MESSAGE_LENGTH = MessageLimit.MAX_TEXT_LENGTH diff --git a/freqtrade/util/__init__.py b/freqtrade/util/__init__.py index fc7cf5f6a..7ddbd873f 100644 --- a/freqtrade/util/__init__.py +++ b/freqtrade/util/__init__.py @@ -1,6 +1,7 @@ from freqtrade.util.datetime_helpers import (dt_floor_day, dt_from_ts, dt_humanize, dt_now, dt_ts, dt_ts_def, dt_utc, format_date, format_ms_time, shorten_date) +from freqtrade.util.formatters import decimals_per_coin, round_coin_value, round_value from freqtrade.util.ft_precise import FtPrecise from freqtrade.util.periodic_cache import PeriodicCache from freqtrade.util.template_renderer import render_template, render_template_with_fallback # noqa @@ -19,4 +20,7 @@ __all__ = [ 'FtPrecise', 'PeriodicCache', 'shorten_date', + 'decimals_per_coin', + 'round_value', + 'round_coin_value', ] diff --git a/freqtrade/util/formatters.py b/freqtrade/util/formatters.py new file mode 100644 index 000000000..c1977c2ba --- /dev/null +++ b/freqtrade/util/formatters.py @@ -0,0 +1,42 @@ +from freqtrade.constants import DECIMAL_PER_COIN_FALLBACK, DECIMALS_PER_COIN + + +def decimals_per_coin(coin: str): + """ + Helper method getting decimal amount for this coin + example usage: f".{decimals_per_coin('USD')}f" + :param coin: Which coin are we printing the price / value for + """ + return DECIMALS_PER_COIN.get(coin, DECIMAL_PER_COIN_FALLBACK) + + +def round_value(value: float, decimals: int, keep_trailing_zeros=False) -> str: + """ + Round value to given decimals + :param value: Value to be rounded + :param decimals: Number of decimals to round to + :param keep_trailing_zeros: Keep trailing zeros "222.200" vs. "222.2" + :return: Rounded value as string + """ + val = f"{value:.{decimals}f}" + if not keep_trailing_zeros: + val = val.rstrip('0').rstrip('.') + return val + + +def round_coin_value( + value: float, coin: str, show_coin_name=True, keep_trailing_zeros=False) -> str: + """ + Get price value for this coin + :param value: Value to be printed + :param coin: Which coin are we printing the price / value for + :param show_coin_name: Return string in format: "222.22 USDT" or "222.22" + :param keep_trailing_zeros: Keep trailing zeros "222.200" vs. "222.2" + :return: Formatted / rounded value (with or without coin name) + """ + val = f"{value:.{decimals_per_coin(coin)}f}" + val = round_value(value, decimals_per_coin(coin), keep_trailing_zeros) + if show_coin_name: + val = f"{val} {coin}" + + return val diff --git a/tests/test_misc.py b/tests/test_misc.py index 8ce7d0ea7..c9a196259 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -7,46 +7,10 @@ from unittest.mock import MagicMock import pandas as pd import pytest -from freqtrade.misc import (dataframe_to_json, decimals_per_coin, deep_merge_dicts, file_dump_json, - file_load_json, is_file_in_dir, json_to_dataframe, pair_to_filename, - parse_db_uri_for_logging, plural, round_coin_value, round_value, - safe_value_fallback, safe_value_fallback2) - - -def test_decimals_per_coin(): - assert decimals_per_coin('USDT') == 3 - assert decimals_per_coin('EUR') == 3 - assert decimals_per_coin('BTC') == 8 - assert decimals_per_coin('ETH') == 5 - - -def test_round_coin_value(): - assert round_coin_value(222.222222, 'USDT') == '222.222 USDT' - assert round_coin_value(222.2, 'USDT', keep_trailing_zeros=True) == '222.200 USDT' - assert round_coin_value(222.2, 'USDT') == '222.2 USDT' - assert round_coin_value(222.12745, 'EUR') == '222.127 EUR' - assert round_coin_value(0.1274512123, 'BTC') == '0.12745121 BTC' - assert round_coin_value(0.1274512123, 'ETH') == '0.12745 ETH' - - assert round_coin_value(222.222222, 'USDT', False) == '222.222' - assert round_coin_value(222.2, 'USDT', False) == '222.2' - assert round_coin_value(222.00, 'USDT', False) == '222' - assert round_coin_value(222.12745, 'EUR', False) == '222.127' - assert round_coin_value(0.1274512123, 'BTC', False) == '0.12745121' - assert round_coin_value(0.1274512123, 'ETH', False) == '0.12745' - assert round_coin_value(222.2, 'USDT', False, True) == '222.200' - - -def test_round_value(): - - assert round_value(222.222222, 3) == '222.222' - assert round_value(222.2, 3) == '222.2' - assert round_value(222.00, 3) == '222' - assert round_value(222.12745, 3) == '222.127' - assert round_value(0.1274512123, 8) == '0.12745121' - assert round_value(0.1274512123, 5) == '0.12745' - assert round_value(222.2, 3, True) == '222.200' - assert round_value(222.2, 0, True) == '222' +from freqtrade.misc import (dataframe_to_json, deep_merge_dicts, file_dump_json, file_load_json, + is_file_in_dir, json_to_dataframe, pair_to_filename, + parse_db_uri_for_logging, plural, safe_value_fallback, + safe_value_fallback2) def test_file_dump_json(mocker) -> None: diff --git a/tests/utils/test_formatters.py b/tests/utils/test_formatters.py new file mode 100644 index 000000000..fce31b12e --- /dev/null +++ b/tests/utils/test_formatters.py @@ -0,0 +1,37 @@ +from freqtrade.util import decimals_per_coin, round_coin_value, round_value + + +def test_decimals_per_coin(): + assert decimals_per_coin('USDT') == 3 + assert decimals_per_coin('EUR') == 3 + assert decimals_per_coin('BTC') == 8 + assert decimals_per_coin('ETH') == 5 + + +def test_round_coin_value(): + assert round_coin_value(222.222222, 'USDT') == '222.222 USDT' + assert round_coin_value(222.2, 'USDT', keep_trailing_zeros=True) == '222.200 USDT' + assert round_coin_value(222.2, 'USDT') == '222.2 USDT' + assert round_coin_value(222.12745, 'EUR') == '222.127 EUR' + assert round_coin_value(0.1274512123, 'BTC') == '0.12745121 BTC' + assert round_coin_value(0.1274512123, 'ETH') == '0.12745 ETH' + + assert round_coin_value(222.222222, 'USDT', False) == '222.222' + assert round_coin_value(222.2, 'USDT', False) == '222.2' + assert round_coin_value(222.00, 'USDT', False) == '222' + assert round_coin_value(222.12745, 'EUR', False) == '222.127' + assert round_coin_value(0.1274512123, 'BTC', False) == '0.12745121' + assert round_coin_value(0.1274512123, 'ETH', False) == '0.12745' + assert round_coin_value(222.2, 'USDT', False, True) == '222.200' + + +def test_round_value(): + + assert round_value(222.222222, 3) == '222.222' + assert round_value(222.2, 3) == '222.2' + assert round_value(222.00, 3) == '222' + assert round_value(222.12745, 3) == '222.127' + assert round_value(0.1274512123, 8) == '0.12745121' + assert round_value(0.1274512123, 5) == '0.12745' + assert round_value(222.2, 3, True) == '222.200' + assert round_value(222.2, 0, True) == '222'