diff --git a/docs/utils.md b/docs/utils.md index 57210ac7e..7ed31376f 100644 --- a/docs/utils.md +++ b/docs/utils.md @@ -521,3 +521,48 @@ Prints JSON data with details for the last best epoch (i.e., the best of all epo ``` freqtrade hyperopt-show --best -n -1 --print-json --no-header ``` + +## Show trades + +Print selected (or all) trades from database to screen. + +``` +usage: freqtrade show-trades [-h] [-v] [--logfile FILE] [-V] [-c PATH] + [-d PATH] [--userdir PATH] [--db-url PATH] + [--trade-ids TRADE_IDS [TRADE_IDS ...]] + [--print-json] + +optional arguments: + -h, --help show this help message and exit + --db-url PATH Override trades database URL, this is useful in custom + deployments (default: `sqlite:///tradesv3.sqlite` for + Live Run mode, `sqlite:///tradesv3.dryrun.sqlite` for + Dry Run). + --trade-ids TRADE_IDS [TRADE_IDS ...] + Specify the list of trade ids. + --print-json Print output in JSON format. + +Common arguments: + -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). + --logfile FILE Log to the file specified. Special values are: + 'syslog', 'journald'. See the documentation for more + details. + -V, --version show program's version number and exit + -c PATH, --config PATH + Specify configuration file (default: + `userdir/config.json` or `config.json` whichever + exists). Multiple --config options may be used. Can be + set to `-` to read config from stdin. + -d PATH, --datadir PATH + Path to directory with historical backtesting data. + --userdir PATH, --user-data-dir PATH + Path to userdata directory. +``` + +### Examples + +Print trades with id 2 and 3 as json + +``` bash +freqtrade show-trades --db-url sqlite:///tradesv3.sqlite --trade-ids 2 3 --print-json +``` diff --git a/freqtrade/commands/__init__.py b/freqtrade/commands/__init__.py index f80c74e05..2d0c7733c 100644 --- a/freqtrade/commands/__init__.py +++ b/freqtrade/commands/__init__.py @@ -19,7 +19,8 @@ from freqtrade.commands.list_commands import (start_list_exchanges, start_list_hyperopts, start_list_markets, start_list_strategies, - start_list_timeframes) + start_list_timeframes, + start_show_trades) from freqtrade.commands.optimize_commands import (start_backtesting, start_edge, start_hyperopt) from freqtrade.commands.pairlist_commands import start_test_pairlist diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index 8c64c5857..a03da00ab 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -64,6 +64,8 @@ ARGS_PLOT_DATAFRAME = ["pairs", "indicators1", "indicators2", "plot_limit", ARGS_PLOT_PROFIT = ["pairs", "timerange", "export", "exportfilename", "db_url", "trade_source", "ticker_interval"] +ARGS_SHOW_TRADES = ["db_url", "trade_ids", "print_json"] + ARGS_HYPEROPT_LIST = ["hyperopt_list_best", "hyperopt_list_profitable", "hyperopt_list_min_trades", "hyperopt_list_max_trades", "hyperopt_list_min_avg_time", "hyperopt_list_max_avg_time", @@ -78,7 +80,7 @@ ARGS_HYPEROPT_SHOW = ["hyperopt_list_best", "hyperopt_list_profitable", "hyperop NO_CONF_REQURIED = ["convert-data", "convert-trade-data", "download-data", "list-timeframes", "list-markets", "list-pairs", "list-strategies", "list-hyperopts", "hyperopt-list", "hyperopt-show", - "plot-dataframe", "plot-profit"] + "plot-dataframe", "plot-profit", "show-trades"] NO_CONF_ALLOWED = ["create-userdir", "list-exchanges", "new-hyperopt", "new-strategy"] @@ -163,7 +165,7 @@ class Arguments: start_list_markets, start_list_strategies, start_list_timeframes, start_new_config, start_new_hyperopt, start_new_strategy, - start_plot_dataframe, start_plot_profit, + start_plot_dataframe, start_plot_profit, start_show_trades, start_backtesting, start_hyperopt, start_edge, start_test_pairlist, start_trading) @@ -330,6 +332,15 @@ class Arguments: plot_profit_cmd.set_defaults(func=start_plot_profit) self._build_args(optionlist=ARGS_PLOT_PROFIT, parser=plot_profit_cmd) + # Add show-trades subcommand + show_trades = subparsers.add_parser( + 'show-trades', + help='Show trades.', + parents=[_common_parser], + ) + show_trades.set_defaults(func=start_show_trades) + self._build_args(optionlist=ARGS_SHOW_TRADES, parser=show_trades) + # Add hyperopt-list subcommand hyperopt_list_cmd = subparsers.add_parser( 'hyperopt-list', diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index 498ea9359..a8f2ffdba 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -217,7 +217,7 @@ AVAILABLE_CLI_OPTIONS = { ), "print_json": Arg( '--print-json', - help='Print best result detailization in JSON format.', + help='Print output in JSON format.', action='store_true', default=False, ), @@ -425,6 +425,11 @@ AVAILABLE_CLI_OPTIONS = { choices=["DB", "file"], default="file", ), + "trade_ids": Arg( + '--trade-ids', + help='Specify the list of trade ids.', + nargs='+', + ), # hyperopt-list, hyperopt-show "hyperopt_list_profitable": Arg( '--profitable', diff --git a/freqtrade/commands/list_commands.py b/freqtrade/commands/list_commands.py index 327901dc0..61d6f7244 100644 --- a/freqtrade/commands/list_commands.py +++ b/freqtrade/commands/list_commands.py @@ -197,3 +197,25 @@ def start_list_markets(args: Dict[str, Any], pairs_only: bool = False) -> None: args.get('list_pairs_print_json', False) or args.get('print_csv', False)): print(f"{summary_str}.") + + +def start_show_trades(args: Dict[str, Any]) -> None: + """ + Show trades + """ + from freqtrade.persistence import init, Trade + import json + config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE) + init(config['db_url'], clean_open_orders=False) + tfilter = [] + + if config.get('trade_ids'): + tfilter.append(Trade.id.in_(config['trade_ids'])) + + trades = Trade.get_trades(tfilter).all() + logger.info(f"Printing {len(trades)} Trades: ") + if config.get('print_json', False): + print(json.dumps([trade.to_json() for trade in trades], indent=4)) + else: + for trade in trades: + print(trade) diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index e5515670d..7edd9bca1 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -351,8 +351,12 @@ class Configuration: self._args_to_config(config, argname='indicators2', logstring='Using indicators2: {}') + self._args_to_config(config, argname='trade_ids', + logstring='Filtering on trade_ids: {}') + self._args_to_config(config, argname='plot_limit', logstring='Limiting plot to: {}') + self._args_to_config(config, argname='trade_source', logstring='Using trades from: {}') diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index 264ae9a63..2796a8b45 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -10,11 +10,13 @@ from freqtrade.commands import (start_convert_data, start_create_userdir, start_list_hyperopts, start_list_markets, start_list_strategies, start_list_timeframes, start_new_hyperopt, start_new_strategy, - start_test_pairlist, start_trading) + start_show_trades, start_test_pairlist, + start_trading) from freqtrade.configuration import setup_utils_configuration from freqtrade.exceptions import OperationalException from freqtrade.state import RunMode -from tests.conftest import (get_args, log_has, log_has_re, patch_exchange, +from tests.conftest import (create_mock_trades, get_args, log_has, log_has_re, + patch_exchange, patched_configuration_load_config_file) @@ -1040,3 +1042,38 @@ def test_convert_data_trades(mocker, testdatadir): assert trades_mock.call_args[1]['convert_from'] == 'jsongz' assert trades_mock.call_args[1]['convert_to'] == 'json' assert trades_mock.call_args[1]['erase'] is False + + +@pytest.mark.usefixtures("init_persistence") +def test_show_trades(mocker, fee, capsys, caplog): + mocker.patch("freqtrade.persistence.init") + create_mock_trades(fee) + args = [ + "show-trades", + "--db-url", + "sqlite:///" + ] + pargs = get_args(args) + pargs['config'] = None + start_show_trades(pargs) + assert log_has("Printing 3 Trades: ", caplog) + captured = capsys.readouterr() + assert "Trade(id=1" in captured.out + assert "Trade(id=2" in captured.out + assert "Trade(id=3" in captured.out + args = [ + "show-trades", + "--db-url", + "sqlite:///", + "--print-json", + "--trade-ids", "1", "2" + ] + pargs = get_args(args) + pargs['config'] = None + start_show_trades(pargs) + + captured = capsys.readouterr() + assert log_has("Printing 2 Trades: ", caplog) + assert '"trade_id": 1' in captured.out + assert '"trade_id": 2' in captured.out + assert '"trade_id": 3' not in captured.out