From ab9506df480e53316b65cd43d72c757e3dc18ab4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 12 Nov 2019 13:54:26 +0100 Subject: [PATCH 1/3] simplify status_table command --- freqtrade/rpc/api_server.py | 2 +- freqtrade/rpc/rpc.py | 16 +++++++--------- freqtrade/rpc/telegram.py | 4 ++-- tests/rpc/test_rpc.py | 12 +++++++----- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/freqtrade/rpc/api_server.py b/freqtrade/rpc/api_server.py index 5167823fd..3b59c9592 100644 --- a/freqtrade/rpc/api_server.py +++ b/freqtrade/rpc/api_server.py @@ -274,7 +274,7 @@ class ApiServer(RPC): stats = self._rpc_daily_profit(timescale, self._config['stake_currency'], - self._config['fiat_display_currency'] + self._config.get('fiat_display_currency', '') ) return self.rest_dump(stats) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 4aed48f74..84e681992 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -3,16 +3,15 @@ This module contains class to define a RPC communications """ import logging from abc import abstractmethod -from datetime import timedelta, datetime, date +from datetime import date, datetime, timedelta from decimal import Decimal from enum import Enum -from typing import Dict, Any, List, Optional +from typing import Any, Dict, List, Optional, Tuple import arrow -from numpy import mean, NAN -from pandas import DataFrame +from numpy import NAN, mean -from freqtrade import TemporaryError, DependencyException +from freqtrade import DependencyException, TemporaryError from freqtrade.misc import shorten_date from freqtrade.persistence import Trade from freqtrade.rpc.fiat_convert import CryptoToFiatConverter @@ -117,7 +116,7 @@ class RPC: results.append(trade_dict) return results - def _rpc_status_table(self) -> DataFrame: + def _rpc_status_table(self, fiat_display_currency: str) -> Tuple[List, List]: trades = Trade.get_open_trades() if not trades: raise RPCException('no active order') @@ -135,12 +134,11 @@ class RPC: trade.pair, shorten_date(arrow.get(trade.open_date).humanize(only_distance=True)), f'{trade_perc:.2f}%' + ]) columns = ['ID', 'Pair', 'Since', 'Profit'] - df_statuses = DataFrame.from_records(trades_list, columns=columns) - df_statuses = df_statuses.set_index(columns[0]) - return df_statuses + return trades_list, columns def _rpc_daily_profit( self, timescale: int, diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 80582a0ce..25422973d 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -234,8 +234,8 @@ class Telegram(RPC): :return: None """ try: - df_statuses = self._rpc_status_table() - message = tabulate(df_statuses, headers='keys', tablefmt='simple') + statlist, head = self._rpc_status_table(self._config.get('fiat_display_currency', '')) + message = tabulate(statlist, headers=head, tablefmt='simple') self._send_msg(f"
{message}
", parse_mode=ParseMode.HTML) except RPCException as e: self._send_msg(str(e)) diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index df2261c1f..06203a3d7 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -109,13 +109,15 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None: freqtradebot.state = State.RUNNING with pytest.raises(RPCException, match=r'.*no active order*'): - rpc._rpc_status_table() + rpc._rpc_status_table('USD') freqtradebot.create_trades() - result = rpc._rpc_status_table() - assert 'instantly' in result['Since'].all() - assert 'ETH/BTC' in result['Pair'].all() - assert '-0.59%' in result['Profit'].all() + result, headers = rpc._rpc_status_table('USD') + assert "Since" in headers + assert "Pair" in headers + assert 'instantly' in result[0][2] + assert 'ETH/BTC' in result[0][1] + assert '-0.59%' in result[0][3] mocker.patch('freqtrade.exchange.Exchange.get_ticker', MagicMock(side_effect=DependencyException(f"Pair 'ETH/BTC' not available"))) From df9bfb6c2e02b476955d137d45c637105ae2ed16 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 12 Nov 2019 14:58:41 +0100 Subject: [PATCH 2/3] Add FIAT currency to status-table --- freqtrade/rpc/rpc.py | 21 +++++++++++++++++---- freqtrade/rpc/telegram.py | 3 ++- tests/rpc/test_rpc.py | 33 ++++++++++++++++++++++++--------- 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 84e681992..f15bf3cd0 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -6,6 +6,7 @@ from abc import abstractmethod from datetime import date, datetime, timedelta from decimal import Decimal from enum import Enum +from math import isnan from typing import Any, Dict, List, Optional, Tuple import arrow @@ -116,7 +117,7 @@ class RPC: results.append(trade_dict) return results - def _rpc_status_table(self, fiat_display_currency: str) -> Tuple[List, List]: + def _rpc_status_table(self, stake_currency, fiat_display_currency: str) -> Tuple[List, List]: trades = Trade.get_open_trades() if not trades: raise RPCException('no active order') @@ -129,15 +130,27 @@ class RPC: except DependencyException: current_rate = NAN trade_perc = (100 * trade.calc_profit_percent(current_rate)) + trade_profit = trade.calc_profit(current_rate) + profit_str = f'{trade_perc:.2f}%' + if self._fiat_converter: + fiat_profit = self._fiat_converter.convert_amount( + trade_profit, + stake_currency, + fiat_display_currency + ) + if fiat_profit and not isnan(fiat_profit): + profit_str += f" ({fiat_profit:.2f})" trades_list.append([ trade.id, trade.pair, shorten_date(arrow.get(trade.open_date).humanize(only_distance=True)), - f'{trade_perc:.2f}%' - + profit_str ]) + profitcol = "Profit" + if self._fiat_converter: + profitcol += " (" + fiat_display_currency + ")" - columns = ['ID', 'Pair', 'Since', 'Profit'] + columns = ['ID', 'Pair', 'Since', profitcol] return trades_list, columns def _rpc_daily_profit( diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 25422973d..8a81848ac 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -234,7 +234,8 @@ class Telegram(RPC): :return: None """ try: - statlist, head = self._rpc_status_table(self._config.get('fiat_display_currency', '')) + statlist, head = self._rpc_status_table(self._config['stake_currency'], + self._config.get('fiat_display_currency', '')) message = tabulate(statlist, headers=head, tablefmt='simple') self._send_msg(f"
{message}
", parse_mode=ParseMode.HTML) except RPCException as e: diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index 06203a3d7..e7f41f6e7 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -96,6 +96,11 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None: def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None: + mocker.patch.multiple( + 'freqtrade.rpc.fiat_convert.Market', + ticker=MagicMock(return_value={'price_usd': 15000.0}), + ) + mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch.multiple( 'freqtrade.exchange.Exchange', @@ -109,24 +114,34 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None: freqtradebot.state = State.RUNNING with pytest.raises(RPCException, match=r'.*no active order*'): - rpc._rpc_status_table('USD') + rpc._rpc_status_table(default_conf['stake_currency'], 'USD') freqtradebot.create_trades() - result, headers = rpc._rpc_status_table('USD') + + result, headers = rpc._rpc_status_table(default_conf['stake_currency'], 'USD') assert "Since" in headers assert "Pair" in headers - assert 'instantly' in result[0][2] - assert 'ETH/BTC' in result[0][1] - assert '-0.59%' in result[0][3] + assert 'instantly' == result[0][2] + assert 'ETH/BTC' == result[0][1] + assert '-0.59%' == result[0][3] + # Test with fiatconvert + + rpc._fiat_converter = CryptoToFiatConverter() + result, headers = rpc._rpc_status_table(default_conf['stake_currency'], 'USD') + assert "Since" in headers + assert "Pair" in headers + assert 'instantly' == result[0][2] + assert 'ETH/BTC' == result[0][1] + assert '-0.59% (-0.09)' == result[0][3] mocker.patch('freqtrade.exchange.Exchange.get_ticker', MagicMock(side_effect=DependencyException(f"Pair 'ETH/BTC' not available"))) # invalidate ticker cache rpc._freqtrade.exchange._cached_ticker = {} - result = rpc._rpc_status_table() - assert 'instantly' in result['Since'].all() - assert 'ETH/BTC' in result['Pair'].all() - assert 'nan%' in result['Profit'].all() + result, headers = rpc._rpc_status_table(default_conf['stake_currency'], 'USD') + assert 'instantly' == result[0][2] + assert 'ETH/BTC' == result[0][1] + assert 'nan%' == result[0][3] def test_rpc_daily_profit(default_conf, update, ticker, fee, From 11f7ab61b9cf7958f44f2480c11cc787c1c21fb8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 12 Nov 2019 15:11:31 +0100 Subject: [PATCH 3/3] Remove decimal import from rpc --- freqtrade/rpc/rpc.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index f15bf3cd0..5ab92cf33 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -4,7 +4,6 @@ This module contains class to define a RPC communications import logging from abc import abstractmethod from datetime import date, datetime, timedelta -from decimal import Decimal from enum import Enum from math import isnan from typing import Any, Dict, List, Optional, Tuple @@ -230,7 +229,7 @@ class RPC: profit_percent = trade.calc_profit_percent(rate=current_rate) profit_all_coin.append( - trade.calc_profit(rate=Decimal(trade.close_rate or current_rate)) + trade.calc_profit(rate=trade.close_rate or current_rate) ) profit_all_perc.append(profit_percent)