From 0a14d5ec467bdab197d1d100446f7c4dd5fdb698 Mon Sep 17 00:00:00 2001 From: Ork Blutt Date: Sun, 5 Apr 2020 16:14:02 +0200 Subject: [PATCH 01/12] trades history RPC --- freqtrade/rpc/api_server.py | 16 ++++++++++++- freqtrade/rpc/rpc.py | 47 +++++++++++++++++++++++++++++++++++++ scripts/rest_client.py | 7 ++++++ 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/freqtrade/rpc/api_server.py b/freqtrade/rpc/api_server.py index 8f4cc4787..7e0cdd71d 100644 --- a/freqtrade/rpc/api_server.py +++ b/freqtrade/rpc/api_server.py @@ -173,7 +173,8 @@ class ApiServer(RPC): view_func=self._show_config, methods=['GET']) self.app.add_url_rule(f'{BASE_URI}/ping', 'ping', view_func=self._ping, methods=['GET']) - + self.app.add_url_rule(f'{BASE_URI}/trades', 'trades', + view_func=self._trades, methods=['GET']) # Combined actions and infos self.app.add_url_rule(f'{BASE_URI}/blacklist', 'blacklist', view_func=self._blacklist, methods=['GET', 'POST']) @@ -357,6 +358,19 @@ class ApiServer(RPC): results = self._rpc_balance(self._config['stake_currency'], self._config.get('fiat_display_currency', '')) return self.rest_dump(results) + + @require_login + @rpc_catch_errors + def _trades(self): + """ + Handler for /trades. + + Returns the X last trades in json format + """ + last_trades_number = request.args.get('last_trades_number', 0) + last_trades_number = int(last_trades_number) + results = self._rpc_trade_history(last_trades_number) + return self.rest_dump(results) @require_login @rpc_catch_errors diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index a0f50b070..b0c045e4a 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -226,6 +226,53 @@ class RPC: for key, value in profit_days.items() ] + def _rpc_trade_history( + self, last_trades_number: int) -> List[List[Any]]: + """ Returns the X last trades """ + if last_trades_number > 0: + trades = Trade.get_trades().order_by(Trade.id.desc()).limit(last_trades_number) + else: + trades = Trade.get_trades().order_by(Trade.id.desc()).all() + + output = [] + + for trade in trades: + output.append({ + 'id': trade.id, + 'pair': trade.pair, + 'exchange': trade.exchange, + 'is_open': trade.is_open if trade.is_open is not None else 0, + 'open_rate': trade.open_rate, + 'close_rate': trade.close_rate, + 'fee_open': trade.fee_open, + 'fee_close': trade.fee_close, + 'open_rate_requested': trade.open_rate_requested, + 'open_trade_price': trade.open_trade_price, + 'close_rate_requested': trade.close_rate_requested, + 'close_profit': trade.close_profit, + 'close_profit_abs': trade.close_profit_abs, + 'stake_amount': trade.stake_amount, + 'amount': trade.amount, + 'open_date': trade.open_date, + 'close_date': trade.close_date, + 'open_order_id': trade.open_order_id, + 'stop_loss': trade.stop_loss, + 'stop_loss_pct': trade.stop_loss_pct, + 'initial_stop_loss': trade.initial_stop_loss, + 'initial_stop_loss_pct': trade.initial_stop_loss_pct, + 'stoploss_order_id': trade.stoploss_order_id, + 'stoploss_last_update': trade.stoploss_last_update, + 'max_rate': trade.max_rate, + 'min_rate': trade.min_rate, + 'sell_reason': trade.sell_reason, + 'strategy': trade.strategy, + 'ticker_interval': trade.ticker_interval, + }) + + return { + "trades" : output + } + def _rpc_trade_statistics( self, stake_currency: str, fiat_display_currency: str) -> Dict[str, Any]: """ Returns cumulative profit statistics """ diff --git a/scripts/rest_client.py b/scripts/rest_client.py index ccb33604f..5cbdd8e07 100755 --- a/scripts/rest_client.py +++ b/scripts/rest_client.py @@ -156,6 +156,13 @@ class FtRestClient(): """ return self._get("show_config") + def history(self, number=None): + """Return the amount of open trades. + + :return: json object + """ + return self._get("trades", params={"last_trades_number": number} if number else 0) + def whitelist(self): """Show the current whitelist. From 15c45b984d20d3079875d4b1480e9bac0067b7cd Mon Sep 17 00:00:00 2001 From: Ork Blutt Date: Sun, 5 Apr 2020 16:47:46 +0200 Subject: [PATCH 02/12] removing whitespace --- freqtrade/rpc/api_server.py | 2 +- freqtrade/rpc/rpc.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/rpc/api_server.py b/freqtrade/rpc/api_server.py index 7e0cdd71d..d2fb5bfad 100644 --- a/freqtrade/rpc/api_server.py +++ b/freqtrade/rpc/api_server.py @@ -358,7 +358,7 @@ class ApiServer(RPC): results = self._rpc_balance(self._config['stake_currency'], self._config.get('fiat_display_currency', '')) return self.rest_dump(results) - + @require_login @rpc_catch_errors def _trades(self): diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index b0c045e4a..a3506816b 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -270,7 +270,7 @@ class RPC: }) return { - "trades" : output + "trades": output } def _rpc_trade_statistics( From 8555c5b2110b29a65d20843fa1a66bf79a3a8219 Mon Sep 17 00:00:00 2001 From: Ork Blutt Date: Sun, 5 Apr 2020 17:03:51 +0200 Subject: [PATCH 03/12] fix return value --- freqtrade/rpc/rpc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index a3506816b..01e593e82 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -227,7 +227,7 @@ class RPC: ] def _rpc_trade_history( - self, last_trades_number: int) -> List[List[Any]]: + self, last_trades_number: int) -> Dict[str, List[Dict[str, Any]]]: """ Returns the X last trades """ if last_trades_number > 0: trades = Trade.get_trades().order_by(Trade.id.desc()).limit(last_trades_number) From 6256025c73ae59ce9f9f3c9e52216bd157db0a22 Mon Sep 17 00:00:00 2001 From: Ork Blutt Date: Mon, 6 Apr 2020 11:00:31 +0200 Subject: [PATCH 04/12] various adjustement from PR discussion --- freqtrade/persistence.py | 15 +++++++++++++- freqtrade/rpc/api_server.py | 5 ++--- freqtrade/rpc/rpc.py | 41 ++++++------------------------------- scripts/rest_client.py | 7 ++++--- 4 files changed, 26 insertions(+), 42 deletions(-) diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index 0d668596c..b0ef4bd8f 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -188,7 +188,7 @@ class Trade(_DECL_BASE): fee_close = Column(Float, nullable=False, default=0.0) open_rate = Column(Float) open_rate_requested = Column(Float) - # open_trade_price - calcuated via _calc_open_trade_price + # open_trade_price - calculated via _calc_open_trade_price open_trade_price = Column(Float) close_rate = Column(Float) close_rate_requested = Column(Float) @@ -233,6 +233,9 @@ class Trade(_DECL_BASE): return { 'trade_id': self.id, 'pair': self.pair, + 'is_open': self.is_open, + 'fee_open': self.fee_open, + 'fee_close': self.fee_close, 'open_date_hum': arrow.get(self.open_date).humanize(), 'open_date': self.open_date.strftime("%Y-%m-%d %H:%M:%S"), 'close_date_hum': (arrow.get(self.close_date).humanize() @@ -240,14 +243,24 @@ class Trade(_DECL_BASE): 'close_date': (self.close_date.strftime("%Y-%m-%d %H:%M:%S") if self.close_date else None), 'open_rate': self.open_rate, + 'open_rate_requested': self.open_rate_requested, + 'open_trade_price': self.open_trade_price, 'close_rate': self.close_rate, + 'close_rate_requested': self.close_rate_requested, 'amount': round(self.amount, 8), 'stake_amount': round(self.stake_amount, 8), + 'close_profit': self.close_profit, + 'sell_reason': self.sell_reason, 'stop_loss': self.stop_loss, 'stop_loss_pct': (self.stop_loss_pct * 100) if self.stop_loss_pct else None, 'initial_stop_loss': self.initial_stop_loss, 'initial_stop_loss_pct': (self.initial_stop_loss_pct * 100 if self.initial_stop_loss_pct else None), + 'min_rate': self.min_rate, + 'max_rate': self.max_rate, + 'strategy': self.strategy, + 'ticker_interval': self.ticker_interval, + 'open_order_id': self.open_order_id, } def adjust_min_max_rates(self, current_price: float) -> None: diff --git a/freqtrade/rpc/api_server.py b/freqtrade/rpc/api_server.py index d2fb5bfad..0335bb151 100644 --- a/freqtrade/rpc/api_server.py +++ b/freqtrade/rpc/api_server.py @@ -367,9 +367,8 @@ class ApiServer(RPC): Returns the X last trades in json format """ - last_trades_number = request.args.get('last_trades_number', 0) - last_trades_number = int(last_trades_number) - results = self._rpc_trade_history(last_trades_number) + limit = int(request.args.get('limit', 0)) + results = self._rpc_trade_history(limit) return self.rest_dump(results) @require_login diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 01e593e82..b78856265 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -227,50 +227,21 @@ class RPC: ] def _rpc_trade_history( - self, last_trades_number: int) -> Dict[str, List[Dict[str, Any]]]: + self, limit: int) -> Dict[str, List[Dict[str, Any]]]: """ Returns the X last trades """ - if last_trades_number > 0: - trades = Trade.get_trades().order_by(Trade.id.desc()).limit(last_trades_number) + if limit > 0: + trades = Trade.get_trades().order_by(Trade.id.desc()).limit(limit) else: trades = Trade.get_trades().order_by(Trade.id.desc()).all() output = [] for trade in trades: - output.append({ - 'id': trade.id, - 'pair': trade.pair, - 'exchange': trade.exchange, - 'is_open': trade.is_open if trade.is_open is not None else 0, - 'open_rate': trade.open_rate, - 'close_rate': trade.close_rate, - 'fee_open': trade.fee_open, - 'fee_close': trade.fee_close, - 'open_rate_requested': trade.open_rate_requested, - 'open_trade_price': trade.open_trade_price, - 'close_rate_requested': trade.close_rate_requested, - 'close_profit': trade.close_profit, - 'close_profit_abs': trade.close_profit_abs, - 'stake_amount': trade.stake_amount, - 'amount': trade.amount, - 'open_date': trade.open_date, - 'close_date': trade.close_date, - 'open_order_id': trade.open_order_id, - 'stop_loss': trade.stop_loss, - 'stop_loss_pct': trade.stop_loss_pct, - 'initial_stop_loss': trade.initial_stop_loss, - 'initial_stop_loss_pct': trade.initial_stop_loss_pct, - 'stoploss_order_id': trade.stoploss_order_id, - 'stoploss_last_update': trade.stoploss_last_update, - 'max_rate': trade.max_rate, - 'min_rate': trade.min_rate, - 'sell_reason': trade.sell_reason, - 'strategy': trade.strategy, - 'ticker_interval': trade.ticker_interval, - }) + output.append(trade.to_json()) return { - "trades": output + "trades": output, + "trades_count": len(output) } def _rpc_trade_statistics( diff --git a/scripts/rest_client.py b/scripts/rest_client.py index 5cbdd8e07..116c00063 100755 --- a/scripts/rest_client.py +++ b/scripts/rest_client.py @@ -156,12 +156,13 @@ class FtRestClient(): """ return self._get("show_config") - def history(self, number=None): - """Return the amount of open trades. + def history(self, limit=None): + """Return trades history. + :param limit: Limits trades to the X last trades . No limit to get all the trades. :return: json object """ - return self._get("trades", params={"last_trades_number": number} if number else 0) + return self._get("trades", params={"limit": limit} if limit else 0) def whitelist(self): """Show the current whitelist. From 815660c0700726d7c7cb9a8b82bf9e76186f016f Mon Sep 17 00:00:00 2001 From: Ork Blutt Date: Mon, 6 Apr 2020 11:32:00 +0200 Subject: [PATCH 05/12] fix tests --- tests/rpc/test_rpc.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index 47ffb771b..875a234b2 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -49,6 +49,18 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None: 'base_currency': 'BTC', 'open_date': ANY, 'open_date_hum': ANY, + 'is_open': ANY, + 'fee_open': ANY, + 'fee_close': ANY, + 'open_rate_requested': ANY, + 'open_trade_price': ANY, + 'close_rate_requested': ANY, + 'sell_reason': ANY, + 'min_rate': ANY, + 'max_rate': ANY, + 'strategy': ANY, + 'ticker_interval': ANY, + 'open_order_id': ANY, 'close_date': None, 'close_date_hum': None, 'open_rate': 1.098e-05, @@ -76,6 +88,18 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None: 'base_currency': 'BTC', 'open_date': ANY, 'open_date_hum': ANY, + 'is_open': ANY, + 'fee_open': ANY, + 'fee_close': ANY, + 'open_rate_requested': ANY, + 'open_trade_price': ANY, + 'close_rate_requested': ANY, + 'sell_reason': ANY, + 'min_rate': ANY, + 'max_rate': ANY, + 'strategy': ANY, + 'ticker_interval': ANY, + 'open_order_id': ANY, 'close_date': None, 'close_date_hum': None, 'open_rate': 1.098e-05, From c1f9595086b3a3b2f7871ac0818c878a9c11b876 Mon Sep 17 00:00:00 2001 From: Ork Blutt Date: Mon, 6 Apr 2020 15:49:24 +0200 Subject: [PATCH 06/12] fix broken tests --- tests/rpc/test_rpc_apiserver.py | 33 +++++++++++++++++++++++++++++++-- tests/test_persistence.py | 30 ++++++++++++++++++++++++++++-- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index e0abd886d..79073825d 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -444,7 +444,22 @@ def test_api_status(botclient, mocker, ticker, fee, markets): 'stake_amount': 0.001, 'stop_loss': 0.0, 'stop_loss_pct': None, - 'trade_id': 1}] + 'trade_id': 1, + 'close_rate_requested': None, + 'current_profit': -0.41, + 'current_rate': 1.099e-05, + 'fee_close': 0.0025, + 'fee_open': 0.0025, + 'open_date': ANY, + 'is_open': True, + 'max_rate': 0.0, + 'min_rate': None, + 'open_order_id': ANY, + 'open_rate_requested': 1.098e-05, + 'open_trade_price': 0.0010025, + 'sell_reason': None, + 'strategy': 'DefaultStrategy', + 'ticker_interval': 5}] def test_api_version(botclient): @@ -533,7 +548,21 @@ def test_api_forcebuy(botclient, mocker, fee): 'stake_amount': 1, 'stop_loss': None, 'stop_loss_pct': None, - 'trade_id': None} + 'trade_id': None, + 'close_profit': None, + 'close_rate_requested': None, + 'fee_close': 0.0025, + 'fee_open': 0.0025, + 'is_open': False, + 'max_rate': None, + 'min_rate': None, + 'open_order_id': '123456', + 'open_rate_requested': None, + 'open_trade_price': 0.2460546025, + 'sell_reason': None, + 'strategy': None, + 'ticker_interval': None + } def test_api_forcesell(botclient, mocker, ticker, fee, markets): diff --git a/tests/test_persistence.py b/tests/test_persistence.py index 991922cba..c6de10e3d 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -777,18 +777,31 @@ def test_to_json(default_conf, fee): assert result == {'trade_id': None, 'pair': 'ETH/BTC', + 'is_open': None, 'open_date_hum': '2 hours ago', 'open_date': trade.open_date.strftime("%Y-%m-%d %H:%M:%S"), + 'open_order_id': 'dry_run_buy_12345', 'close_date_hum': None, 'close_date': None, 'open_rate': 0.123, + 'open_rate_requested': None, + 'open_trade_price': 15.1668225, + 'fee_close': 0.0025, + 'fee_open': 0.0025, 'close_rate': None, + 'close_rate_requested': None, 'amount': 123.0, 'stake_amount': 0.001, + 'close_profit': None, + 'sell_reason': None, 'stop_loss': None, 'stop_loss_pct': None, 'initial_stop_loss': None, - 'initial_stop_loss_pct': None} + 'initial_stop_loss_pct': None, + 'min_rate': None, + 'max_rate': None, + 'strategy': None, + 'ticker_interval': None} # Simulate dry_run entries trade = Trade( @@ -819,7 +832,20 @@ def test_to_json(default_conf, fee): 'stop_loss': None, 'stop_loss_pct': None, 'initial_stop_loss': None, - 'initial_stop_loss_pct': None} + 'initial_stop_loss_pct': None, + 'close_profit': None, + 'close_rate_requested': None, + 'fee_close': 0.0025, + 'fee_open': 0.0025, + 'is_open': None, + 'max_rate': None, + 'min_rate': None, + 'open_order_id': None, + 'open_rate_requested': None, + 'open_trade_price': 12.33075, + 'sell_reason': None, + 'strategy': None, + 'ticker_interval': None} def test_stoploss_reinitialization(default_conf, fee): From 2444fb9cd6afe8fe9cd086872d7e6d0b29e95ab7 Mon Sep 17 00:00:00 2001 From: Ork Blutt Date: Mon, 6 Apr 2020 15:56:57 +0200 Subject: [PATCH 07/12] fix broken tests: remove duplicated value --- tests/rpc/test_rpc_apiserver.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 79073825d..c96f68f29 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -446,7 +446,6 @@ def test_api_status(botclient, mocker, ticker, fee, markets): 'stop_loss_pct': None, 'trade_id': 1, 'close_rate_requested': None, - 'current_profit': -0.41, 'current_rate': 1.099e-05, 'fee_close': 0.0025, 'fee_open': 0.0025, From 200111fef6b4b8ff90818a4e76d6caa207fb4034 Mon Sep 17 00:00:00 2001 From: Ork Blutt Date: Mon, 6 Apr 2020 16:07:43 +0200 Subject: [PATCH 08/12] fix method return value --- freqtrade/rpc/rpc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index b78856265..35386760d 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -227,7 +227,7 @@ class RPC: ] def _rpc_trade_history( - self, limit: int) -> Dict[str, List[Dict[str, Any]]]: + self, limit: int) -> Dict: """ Returns the X last trades """ if limit > 0: trades = Trade.get_trades().order_by(Trade.id.desc()).limit(limit) From bdc85ec89b23a99abebe8722da799d81c42a208c Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 7 Apr 2020 19:42:16 +0200 Subject: [PATCH 09/12] Move create_mock_tests to conftest and add test for test_trade-history --- tests/conftest.py | 46 +++++++++++++++++++++++++++++++++ tests/data/test_btanalysis.py | 2 +- tests/rpc/test_rpc.py | 28 +++++++++++++++++++- tests/test_persistence.py | 48 +---------------------------------- 4 files changed, 75 insertions(+), 49 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 64d0cd5ee..da1fbd6d4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -166,6 +166,52 @@ def patch_get_signal(freqtrade: FreqtradeBot, value=(True, False)) -> None: freqtrade.exchange.refresh_latest_ohlcv = lambda p: None +def create_mock_trades(fee): + """ + Create some fake trades ... + """ + # Simulate dry_run entries + trade = Trade( + pair='ETH/BTC', + stake_amount=0.001, + amount=123.0, + fee_open=fee.return_value, + fee_close=fee.return_value, + open_rate=0.123, + exchange='bittrex', + open_order_id='dry_run_buy_12345' + ) + Trade.session.add(trade) + + trade = Trade( + pair='ETC/BTC', + stake_amount=0.001, + amount=123.0, + fee_open=fee.return_value, + fee_close=fee.return_value, + open_rate=0.123, + close_rate=0.128, + close_profit=0.005, + exchange='bittrex', + is_open=False, + open_order_id='dry_run_sell_12345' + ) + Trade.session.add(trade) + + # Simulate prod entry + trade = Trade( + pair='ETC/BTC', + stake_amount=0.001, + amount=123.0, + fee_open=fee.return_value, + fee_close=fee.return_value, + open_rate=0.123, + exchange='bittrex', + open_order_id='prod_buy_12345' + ) + Trade.session.add(trade) + + @pytest.fixture(autouse=True) def patch_coingekko(mocker) -> None: """ diff --git a/tests/data/test_btanalysis.py b/tests/data/test_btanalysis.py index 463e5ae36..0edad8e78 100644 --- a/tests/data/test_btanalysis.py +++ b/tests/data/test_btanalysis.py @@ -15,7 +15,7 @@ from freqtrade.data.btanalysis import (BT_DATA_COLUMNS, load_backtest_data, load_trades, load_trades_from_db) from freqtrade.data.history import load_data, load_pair_history -from tests.test_persistence import create_mock_trades +from tests.conftest import create_mock_trades def test_load_backtest_data(testdatadir): diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index 875a234b2..d2af4bd87 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -13,7 +13,7 @@ from freqtrade.persistence import Trade from freqtrade.rpc import RPC, RPCException from freqtrade.rpc.fiat_convert import CryptoToFiatConverter from freqtrade.state import State -from tests.conftest import get_patched_freqtradebot, patch_get_signal +from tests.conftest import get_patched_freqtradebot, patch_get_signal, create_mock_trades # Functions for recurrent object patching @@ -211,6 +211,32 @@ def test_rpc_daily_profit(default_conf, update, ticker, fee, rpc._rpc_daily_profit(0, stake_currency, fiat_display_currency) +def test_rpc_trade_history(mocker, default_conf, markets, fee): + mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + markets=PropertyMock(return_value=markets) + ) + + freqtradebot = get_patched_freqtradebot(mocker, default_conf) + create_mock_trades(fee) + rpc = RPC(freqtradebot) + rpc._fiat_converter = CryptoToFiatConverter() + trades = rpc._rpc_trade_history(2) + assert len(trades['trades']) == 2 + assert trades['trades_count'] == 2 + assert isinstance(trades['trades'][0], dict) + assert isinstance(trades['trades'][1], dict) + + trades = rpc._rpc_trade_history(0) + assert len(trades['trades']) == 3 + assert trades['trades_count'] == 3 + # The first trade is for ETH ... sorting is descending + assert trades['trades'][-1]['pair'] == 'ETH/BTC' + assert trades['trades'][0]['pair'] == 'ETC/BTC' + assert trades['trades'][1]['pair'] == 'ETC/BTC' + + def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee, limit_buy_order, limit_sell_order, mocker) -> None: mocker.patch.multiple( diff --git a/tests/test_persistence.py b/tests/test_persistence.py index c6de10e3d..ceac24356 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -9,53 +9,7 @@ from sqlalchemy import create_engine from freqtrade import constants from freqtrade.exceptions import OperationalException from freqtrade.persistence import Trade, clean_dry_run_db, init -from tests.conftest import log_has - - -def create_mock_trades(fee): - """ - Create some fake trades ... - """ - # Simulate dry_run entries - trade = Trade( - pair='ETH/BTC', - stake_amount=0.001, - amount=123.0, - fee_open=fee.return_value, - fee_close=fee.return_value, - open_rate=0.123, - exchange='bittrex', - open_order_id='dry_run_buy_12345' - ) - Trade.session.add(trade) - - trade = Trade( - pair='ETC/BTC', - stake_amount=0.001, - amount=123.0, - fee_open=fee.return_value, - fee_close=fee.return_value, - open_rate=0.123, - close_rate=0.128, - close_profit=0.005, - exchange='bittrex', - is_open=False, - open_order_id='dry_run_sell_12345' - ) - Trade.session.add(trade) - - # Simulate prod entry - trade = Trade( - pair='ETC/BTC', - stake_amount=0.001, - amount=123.0, - fee_open=fee.return_value, - fee_close=fee.return_value, - open_rate=0.123, - exchange='bittrex', - open_order_id='prod_buy_12345' - ) - Trade.session.add(trade) +from tests.conftest import log_has, create_mock_trades def test_init_create_session(default_conf): From 296c616ce7c2595ec65ba11d4c0ad0d7e670721f Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 7 Apr 2020 19:50:13 +0200 Subject: [PATCH 10/12] Add test for api-trades call --- tests/rpc/test_rpc_apiserver.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index c96f68f29..6548790cb 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -13,7 +13,7 @@ from freqtrade.__init__ import __version__ from freqtrade.persistence import Trade from freqtrade.rpc.api_server import BASE_URI, ApiServer from freqtrade.state import State -from tests.conftest import get_patched_freqtradebot, log_has, patch_get_signal +from tests.conftest import get_patched_freqtradebot, log_has, patch_get_signal, create_mock_trades _TEST_USER = "FreqTrader" _TEST_PASS = "SuperSecurePassword1!" @@ -302,6 +302,30 @@ def test_api_daily(botclient, mocker, ticker, fee, markets): assert rc.json[0][0] == str(datetime.utcnow().date()) +def test_api_trades(botclient, mocker, ticker, fee, markets): + ftbot, client = botclient + patch_get_signal(ftbot, (True, False)) + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + markets=PropertyMock(return_value=markets) + ) + rc = client_get(client, f"{BASE_URI}/trades") + assert_response(rc) + assert len(rc.json) == 2 + assert rc.json['trades_count'] == 0 + + create_mock_trades(fee) + + rc = client_get(client, f"{BASE_URI}/trades") + assert_response(rc) + assert len(rc.json['trades']) == 3 + assert rc.json['trades_count'] == 3 + rc = client_get(client, f"{BASE_URI}/trades?limit=2") + assert_response(rc) + assert len(rc.json['trades']) == 2 + assert rc.json['trades_count'] == 2 + + def test_api_edge_disabled(botclient, mocker, ticker, fee, markets): ftbot, client = botclient patch_get_signal(ftbot, (True, False)) From 492c2799dc78c38ece251c06f4377fdf03113b61 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 7 Apr 2020 19:52:34 +0200 Subject: [PATCH 11/12] Rename rest-client script history to trades --- scripts/rest_client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/rest_client.py b/scripts/rest_client.py index 116c00063..b26c32479 100755 --- a/scripts/rest_client.py +++ b/scripts/rest_client.py @@ -156,10 +156,10 @@ class FtRestClient(): """ return self._get("show_config") - def history(self, limit=None): + def trades(self, limit=None): """Return trades history. - :param limit: Limits trades to the X last trades . No limit to get all the trades. + :param limit: Limits trades to the X last trades. No limit to get all the trades. :return: json object """ return self._get("trades", params={"limit": limit} if limit else 0) From 02192f28cd62a1fe4b0bf95545f718079122b715 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 8 Apr 2020 07:56:21 +0200 Subject: [PATCH 12/12] Small stylistic updates --- freqtrade/rpc/rpc.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 35386760d..8645e466e 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -226,18 +226,14 @@ class RPC: for key, value in profit_days.items() ] - def _rpc_trade_history( - self, limit: int) -> Dict: + def _rpc_trade_history(self, limit: int) -> Dict: """ Returns the X last trades """ if limit > 0: trades = Trade.get_trades().order_by(Trade.id.desc()).limit(limit) else: trades = Trade.get_trades().order_by(Trade.id.desc()).all() - output = [] - - for trade in trades: - output.append(trade.to_json()) + output = [trade.to_json() for trade in trades] return { "trades": output,