Merge pull request #10105 from freqtrade/feat/humanize

Replace arrow with humanize
This commit is contained in:
Matthias
2024-04-23 09:46:35 +02:00
committed by GitHub
10 changed files with 35 additions and 34 deletions
+2 -2
View File
@@ -44,7 +44,7 @@ from freqtrade.misc import (chunks, deep_merge_dicts, file_dump_json, file_load_
safe_value_fallback2) safe_value_fallback2)
from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist
from freqtrade.util import dt_from_ts, dt_now from freqtrade.util import dt_from_ts, dt_now
from freqtrade.util.datetime_helpers import dt_humanize, dt_ts from freqtrade.util.datetime_helpers import dt_humanize_delta, dt_ts
from freqtrade.util.periodic_cache import PeriodicCache from freqtrade.util.periodic_cache import PeriodicCache
@@ -2008,7 +2008,7 @@ class Exchange:
logger.debug( logger.debug(
"one_call: %s msecs (%s)", "one_call: %s msecs (%s)",
one_call, one_call,
dt_humanize(dt_now() - timedelta(milliseconds=one_call), only_distance=True) dt_humanize_delta(dt_now() - timedelta(milliseconds=one_call))
) )
input_coroutines = [self._async_get_candle_history( input_coroutines = [self._async_get_candle_history(
pair, timeframe, candle_type, since) for since in pair, timeframe, candle_type, since) for since in
+5 -5
View File
@@ -30,8 +30,8 @@ from freqtrade.persistence.models import PairLock
from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist
from freqtrade.rpc.fiat_convert import CryptoToFiatConverter from freqtrade.rpc.fiat_convert import CryptoToFiatConverter
from freqtrade.rpc.rpc_types import RPCSendMsg from freqtrade.rpc.rpc_types import RPCSendMsg
from freqtrade.util import (decimals_per_coin, dt_humanize, dt_now, dt_ts_def, format_date, from freqtrade.util import decimals_per_coin, dt_now, dt_ts_def, format_date, shorten_date
shorten_date) from freqtrade.util.datetime_helpers import dt_humanize_delta
from freqtrade.wallets import PositionWallet, Wallet from freqtrade.wallets import PositionWallet, Wallet
@@ -307,7 +307,7 @@ class RPC:
detail_trade = [ detail_trade = [
f'{trade.id} {direction_str}', f'{trade.id} {direction_str}',
trade.pair + active_attempt_side_symbols_str, trade.pair + active_attempt_side_symbols_str,
shorten_date(dt_humanize(trade.open_date, only_distance=True)), shorten_date(dt_humanize_delta(trade.open_date_utc)),
profit_str profit_str
] ]
@@ -599,10 +599,10 @@ class RPC:
'trade_count': len(trades), 'trade_count': len(trades),
'closed_trade_count': closed_trade_count, 'closed_trade_count': closed_trade_count,
'first_trade_date': format_date(first_date), 'first_trade_date': format_date(first_date),
'first_trade_humanized': dt_humanize(first_date) if first_date else '', 'first_trade_humanized': dt_humanize_delta(first_date) if first_date else '',
'first_trade_timestamp': dt_ts_def(first_date, 0), 'first_trade_timestamp': dt_ts_def(first_date, 0),
'latest_trade_date': format_date(last_date), 'latest_trade_date': format_date(last_date),
'latest_trade_humanized': dt_humanize(last_date) if last_date else '', 'latest_trade_humanized': dt_humanize_delta(last_date) if last_date else '',
'latest_trade_timestamp': dt_ts_def(last_date, 0), 'latest_trade_timestamp': dt_ts_def(last_date, 0),
'avg_duration': str(timedelta(seconds=sum(durations) / num)).split('.')[0], 'avg_duration': str(timedelta(seconds=sum(durations) / num)).split('.')[0],
'best_pair': best_pair[0] if best_pair else '', 'best_pair': best_pair[0] if best_pair else '',
+4 -5
View File
@@ -33,7 +33,7 @@ from freqtrade.misc import chunks, plural
from freqtrade.persistence import Trade from freqtrade.persistence import Trade
from freqtrade.rpc import RPC, RPCException, RPCHandler from freqtrade.rpc import RPC, RPCException, RPCHandler
from freqtrade.rpc.rpc_types import RPCEntryMsg, RPCExitMsg, RPCOrderMsg, RPCSendMsg from freqtrade.rpc.rpc_types import RPCEntryMsg, RPCExitMsg, RPCOrderMsg, RPCSendMsg
from freqtrade.util import dt_humanize, fmt_coin, format_date, round_value from freqtrade.util import dt_from_ts, dt_humanize_delta, fmt_coin, format_date, round_value
MAX_MESSAGE_LENGTH = MessageLimit.MAX_TEXT_LENGTH MAX_MESSAGE_LENGTH = MessageLimit.MAX_TEXT_LENGTH
@@ -573,8 +573,7 @@ class Telegram(RPCHandler):
# TODO: This calculation ignores fees. # TODO: This calculation ignores fees.
price_to_1st_entry = ((cur_entry_average - first_avg) / first_avg) price_to_1st_entry = ((cur_entry_average - first_avg) / first_avg)
if is_open: if is_open:
lines.append("({})".format(dt_humanize(order["order_filled_date"], lines.append("({})".format(dt_humanize_delta(order["order_filled_date"])))
granularity=["day", "hour", "minute"])))
lines.append(f"*Amount:* {round_value(cur_entry_amount, 8)} " lines.append(f"*Amount:* {round_value(cur_entry_amount, 8)} "
f"({fmt_coin(order['cost'], quote_currency)})") f"({fmt_coin(order['cost'], quote_currency)})")
lines.append(f"*Average {wording} Price:* {round_value(cur_entry_average, 8)} " lines.append(f"*Average {wording} Price:* {round_value(cur_entry_average, 8)} "
@@ -657,7 +656,7 @@ class Telegram(RPCHandler):
position_adjust = self._config.get('position_adjustment_enable', False) position_adjust = self._config.get('position_adjustment_enable', False)
max_entries = self._config.get('max_entry_position_adjustment', -1) max_entries = self._config.get('max_entry_position_adjustment', -1)
for r in results: for r in results:
r['open_date_hum'] = dt_humanize(r['open_date']) r['open_date_hum'] = dt_humanize_delta(r['open_date'])
r['num_entries'] = len([o for o in r['orders'] if o['ft_is_entry']]) r['num_entries'] = len([o for o in r['orders'] if o['ft_is_entry']])
r['num_exits'] = len([o for o in r['orders'] if not o['ft_is_entry'] r['num_exits'] = len([o for o in r['orders'] if not o['ft_is_entry']
and not o['ft_order_side'] == 'stoploss']) and not o['ft_order_side'] == 'stoploss'])
@@ -1289,7 +1288,7 @@ class Telegram(RPCHandler):
nrecent nrecent
) )
trades_tab = tabulate( trades_tab = tabulate(
[[dt_humanize(trade['close_date']), [[dt_humanize_delta(dt_from_ts(trade['close_timestamp'])),
trade['pair'] + " (#" + str(trade['trade_id']) + ")", trade['pair'] + " (#" + str(trade['trade_id']) + ")",
f"{(trade['close_profit']):.2%} ({trade['close_profit_abs']})"] f"{(trade['close_profit']):.2%} ({trade['close_profit_abs']})"]
for trade in trades['trades']], for trade in trades['trades']],
+3 -3
View File
@@ -1,5 +1,5 @@
from freqtrade.util.datetime_helpers import (dt_floor_day, dt_from_ts, dt_humanize, dt_now, dt_ts, from freqtrade.util.datetime_helpers import (dt_floor_day, dt_from_ts, dt_humanize_delta, dt_now,
dt_ts_def, dt_ts_none, dt_utc, format_date, dt_ts, dt_ts_def, dt_ts_none, dt_utc, format_date,
format_ms_time, shorten_date) format_ms_time, shorten_date)
from freqtrade.util.formatters import decimals_per_coin, fmt_coin, round_value from freqtrade.util.formatters import decimals_per_coin, fmt_coin, round_value
from freqtrade.util.ft_precise import FtPrecise from freqtrade.util.ft_precise import FtPrecise
@@ -11,7 +11,7 @@ from freqtrade.util.template_renderer import render_template, render_template_wi
__all__ = [ __all__ = [
'dt_floor_day', 'dt_floor_day',
'dt_from_ts', 'dt_from_ts',
'dt_humanize', 'dt_humanize_delta',
'dt_now', 'dt_now',
'dt_ts', 'dt_ts',
'dt_ts_def', 'dt_ts_def',
+4 -6
View File
@@ -2,7 +2,7 @@ import re
from datetime import datetime, timezone from datetime import datetime, timezone
from typing import Optional, Union from typing import Optional, Union
import arrow import humanize
from freqtrade.constants import DATETIME_PRINT_FORMAT from freqtrade.constants import DATETIME_PRINT_FORMAT
@@ -76,13 +76,11 @@ def shorten_date(_date: str) -> str:
return new_date return new_date
def dt_humanize(dt: datetime, **kwargs) -> str: def dt_humanize_delta(dt: datetime):
""" """
Return a humanized string for the given datetime. Return a humanized string for the given timedelta.
:param dt: datetime to humanize
:param kwargs: kwargs to pass to arrow's humanize()
""" """
return arrow.get(dt).humanize(**kwargs) return humanize.naturaltime(dt)
def format_date(date: Optional[datetime]) -> str: def format_date(date: Optional[datetime]) -> str:
+1 -1
View File
@@ -9,7 +9,7 @@ SQLAlchemy==2.0.29
python-telegram-bot==21.1.1 python-telegram-bot==21.1.1
# can't be hard-pinned due to telegram-bot pinning httpx with ~ # can't be hard-pinned due to telegram-bot pinning httpx with ~
httpx>=0.24.1 httpx>=0.24.1
arrow==1.3.0 humanize==4.9.0
cachetools==5.3.3 cachetools==5.3.3
requests==2.31.0 requests==2.31.0
urllib3==2.2.1 urllib3==2.2.1
+1 -1
View File
@@ -73,7 +73,7 @@ setup(
'ccxt>=4.2.47', 'ccxt>=4.2.47',
'SQLAlchemy>=2.0.6', 'SQLAlchemy>=2.0.6',
'python-telegram-bot>=20.1', 'python-telegram-bot>=20.1',
'arrow>=1.0.0', 'humanize>=4.0.0',
'cachetools', 'cachetools',
'requests', 'requests',
'httpx>=0.24.1', 'httpx>=0.24.1',
+4 -4
View File
@@ -221,7 +221,7 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None:
result, headers, fiat_profit_sum = rpc._rpc_status_table(default_conf['stake_currency'], 'USD') result, headers, fiat_profit_sum = rpc._rpc_status_table(default_conf['stake_currency'], 'USD')
assert "Since" in headers assert "Since" in headers
assert "Pair" in headers assert "Pair" in headers
assert 'instantly' == result[0][2] assert 'now' == result[0][2]
assert 'ETH/BTC' in result[0][1] assert 'ETH/BTC' in result[0][1]
assert '0.00 (0.00)' == result[0][3] assert '0.00 (0.00)' == result[0][3]
assert '0.00' == f'{fiat_profit_sum:.2f}' assert '0.00' == f'{fiat_profit_sum:.2f}'
@@ -232,7 +232,7 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None:
result, headers, fiat_profit_sum = rpc._rpc_status_table(default_conf['stake_currency'], 'USD') result, headers, fiat_profit_sum = rpc._rpc_status_table(default_conf['stake_currency'], 'USD')
assert "Since" in headers assert "Since" in headers
assert "Pair" in headers assert "Pair" in headers
assert 'instantly' == result[0][2] assert 'now' == result[0][2]
assert 'ETH/BTC' in result[0][1] assert 'ETH/BTC' in result[0][1]
assert '-0.41% (-0.00)' == result[0][3] assert '-0.41% (-0.00)' == result[0][3]
assert '-0.00' == f'{fiat_profit_sum:.2f}' assert '-0.00' == f'{fiat_profit_sum:.2f}'
@@ -243,7 +243,7 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None:
assert "Since" in headers assert "Since" in headers
assert "Pair" in headers assert "Pair" in headers
assert len(result[0]) == 4 assert len(result[0]) == 4
assert 'instantly' == result[0][2] assert 'now' == result[0][2]
assert 'ETH/BTC' in result[0][1] assert 'ETH/BTC' in result[0][1]
assert '-0.41% (-0.06)' == result[0][3] assert '-0.41% (-0.06)' == result[0][3]
assert '-0.06' == f'{fiat_profit_sum:.2f}' assert '-0.06' == f'{fiat_profit_sum:.2f}'
@@ -260,7 +260,7 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None:
mocker.patch(f'{EXMS}.get_rate', mocker.patch(f'{EXMS}.get_rate',
MagicMock(side_effect=ExchangeError("Pair 'ETH/BTC' not available"))) MagicMock(side_effect=ExchangeError("Pair 'ETH/BTC' not available")))
result, headers, fiat_profit_sum = rpc._rpc_status_table(default_conf['stake_currency'], 'USD') result, headers, fiat_profit_sum = rpc._rpc_status_table(default_conf['stake_currency'], 'USD')
assert 'instantly' == result[0][2] assert 'now' == result[0][2]
assert 'ETH/BTC' in result[0][1] assert 'ETH/BTC' in result[0][1]
assert 'nan%' == result[0][3] assert 'nan%' == result[0][3]
assert isnan(fiat_profit_sum) assert isnan(fiat_profit_sum)
+2 -2
View File
@@ -1821,8 +1821,8 @@ async def test_edge_enabled(edge_conf, update, mocker) -> None:
@pytest.mark.parametrize('is_short,regex_pattern', @pytest.mark.parametrize('is_short,regex_pattern',
[(True, r"just now[ ]*XRP\/BTC \(#3\) -1.00% \("), [(True, r"now[ ]*XRP\/BTC \(#3\) -1.00% \("),
(False, r"just now[ ]*XRP\/BTC \(#3\) 1.00% \(")]) (False, r"now[ ]*XRP\/BTC \(#3\) 1.00% \(")])
async def test_telegram_trades(mocker, update, default_conf, fee, is_short, regex_pattern): async def test_telegram_trades(mocker, update, default_conf, fee, is_short, regex_pattern):
telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf) telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf)
+9 -5
View File
@@ -3,8 +3,9 @@ from datetime import datetime, timedelta, timezone
import pytest import pytest
import time_machine import time_machine
from freqtrade.util import (dt_floor_day, dt_from_ts, dt_humanize, dt_now, dt_ts, dt_ts_def, from freqtrade.util import (dt_floor_day, dt_from_ts, dt_now, dt_ts, dt_ts_def, dt_ts_none, dt_utc,
dt_ts_none, dt_utc, format_date, format_ms_time, shorten_date) format_date, format_ms_time, shorten_date)
from freqtrade.util.datetime_helpers import dt_humanize_delta
def test_dt_now(): def test_dt_now():
@@ -68,9 +69,12 @@ def test_shorten_date() -> None:
def test_dt_humanize() -> None: def test_dt_humanize() -> None:
assert dt_humanize(dt_now()) == 'just now' assert dt_humanize_delta(dt_now()) == 'now'
assert dt_humanize(dt_now(), only_distance=True) == 'instantly' assert dt_humanize_delta(dt_now() - timedelta(minutes=50)) == '50 minutes ago'
assert dt_humanize(dt_now() - timedelta(hours=16), only_distance=True) == '16 hours' assert dt_humanize_delta(dt_now() - timedelta(hours=16)) == '16 hours ago'
assert dt_humanize_delta(dt_now() - timedelta(hours=16, minutes=30)) == '16 hours ago'
assert dt_humanize_delta(dt_now() - timedelta(days=16, hours=10, minutes=25)) == '16 days ago'
assert dt_humanize_delta(dt_now() - timedelta(minutes=50)) == '50 minutes ago'
def test_format_ms_time() -> None: def test_format_ms_time() -> None: