diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 1f9a9a5b0..2621bb852 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -751,8 +751,11 @@ class PairLock(_DECL_BASE): def to_json(self) -> Dict[str, Any]: return { 'pair': self.pair, - 'lock_time': self.lock_time, - 'lock_end_time': self.lock_end_time, + 'lock_time': self.lock_time.strftime("%Y-%m-%d %H:%M:%S"), + 'lock_timestamp': int(self.lock_time.replace(tzinfo=timezone.utc).timestamp() * 1000), + 'lock_end_time': self.lock_end_time.strftime("%Y-%m-%d %H:%M:%S"), + 'lock_end_timestamp': int(self.lock_end_time.replace(tzinfo=timezone.utc + ).timestamp() * 1000), 'reason': self.reason, 'active': self.active, } diff --git a/freqtrade/rpc/api_server.py b/freqtrade/rpc/api_server.py index f31d7b0b5..89e0f88c7 100644 --- a/freqtrade/rpc/api_server.py +++ b/freqtrade/rpc/api_server.py @@ -192,6 +192,7 @@ class ApiServer(RPC): self.app.add_url_rule(f'{BASE_URI}/balance', 'balance', view_func=self._balance, methods=['GET']) self.app.add_url_rule(f'{BASE_URI}/count', 'count', view_func=self._count, methods=['GET']) + self.app.add_url_rule(f'{BASE_URI}/locks', 'locks', view_func=self._locks, methods=['GET']) self.app.add_url_rule(f'{BASE_URI}/daily', 'daily', view_func=self._daily, methods=['GET']) self.app.add_url_rule(f'{BASE_URI}/edge', 'edge', view_func=self._edge, methods=['GET']) self.app.add_url_rule(f'{BASE_URI}/logs', 'log', view_func=self._get_logs, methods=['GET']) @@ -350,6 +351,15 @@ class ApiServer(RPC): msg = self._rpc_count() return jsonify(msg) + @require_login + @rpc_catch_errors + def _locks(self): + """ + Handler for /locks. + Returns the number of trades running + """ + return jsonify(self._rpc_locks()) + @require_login @rpc_catch_errors def _daily(self): diff --git a/scripts/rest_client.py b/scripts/rest_client.py index 46966d447..268e81397 100755 --- a/scripts/rest_client.py +++ b/scripts/rest_client.py @@ -111,6 +111,13 @@ class FtRestClient(): """ return self._get("count") + def locks(self): + """Return current locks + + :return: json object + """ + return self._get("locks") + def daily(self, days=None): """Return the amount of open trades. diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index d0e5d3c37..2b4242f5a 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -2,8 +2,9 @@ Unit test file for rpc/api_server.py """ -from datetime import datetime +from datetime import datetime, timedelta from pathlib import Path +from time import sleep from unittest.mock import ANY, MagicMock, PropertyMock import pytest @@ -12,7 +13,7 @@ from requests.auth import _basic_auth_str from freqtrade.__init__ import __version__ from freqtrade.loggers import setup_logging, setup_logging_pre -from freqtrade.persistence import Trade +from freqtrade.persistence import PairLock, Trade from freqtrade.rpc.api_server import BASE_URI, ApiServer from freqtrade.state import State from tests.conftest import create_mock_trades, get_patched_freqtradebot, log_has, patch_get_signal @@ -328,6 +329,30 @@ def test_api_count(botclient, mocker, ticker, fee, markets): assert rc.json["max"] == 1.0 +def test_api_locks(botclient): + ftbot, client = botclient + + rc = client_get(client, f"{BASE_URI}/locks") + assert_response(rc) + + assert 'locks' in rc.json + + assert rc.json['lock_count'] == 0 + assert rc.json['lock_count'] == len(rc.json['locks']) + + PairLock.lock_pair('ETH/BTC', datetime.utcnow() + timedelta(minutes=4), 'randreason') + PairLock.lock_pair('XRP/BTC', datetime.utcnow() + timedelta(minutes=20), 'deadbeef') + + rc = client_get(client, f"{BASE_URI}/locks") + assert_response(rc) + + assert rc.json['lock_count'] == 2 + assert rc.json['lock_count'] == len(rc.json['locks']) + assert 'ETH/BTC' in (rc.json['locks'][0]['pair'], rc.json['locks'][1]['pair']) + assert 'randreason' in (rc.json['locks'][0]['reason'], rc.json['locks'][1]['reason']) + assert 'deadbeef' in (rc.json['locks'][0]['reason'], rc.json['locks'][1]['reason']) + + def test_api_show_config(botclient, mocker): ftbot, client = botclient patch_get_signal(ftbot, (True, False))