From 8bdace68f60ded15f30bf34afd7f41ad8244535b Mon Sep 17 00:00:00 2001 From: Sebastien Moreau Date: Sun, 29 Oct 2017 18:57:48 -0400 Subject: [PATCH] Adds options for /status command --- .editorconfig | 18 -------- bin/run-docker | 74 ------------------------------ freqtrade/rpc/telegram.py | 94 ++++++++++++++++++++++++++++++++++++++- requirements.txt | 3 +- 4 files changed, 95 insertions(+), 94 deletions(-) delete mode 100644 .editorconfig delete mode 100755 bin/run-docker diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 326ade84f..000000000 --- a/.editorconfig +++ /dev/null @@ -1,18 +0,0 @@ -# http://editorconfig.org -root = true - -[*] -charset = utf-8 -end_of_line = lf -indent_size = 4 -indent_style = space -insert_final_newline = true -max_line_length = 80 -trim_trailing_whitespace = true - -[*.md] -max_line_length = 0 -trim_trailing_whitespace = false - -[COMMIT_EDITMSG] -max_line_length = 0 diff --git a/bin/run-docker b/bin/run-docker deleted file mode 100755 index e0874589b..000000000 --- a/bin/run-docker +++ /dev/null @@ -1,74 +0,0 @@ -#!/bin/bash - -# Check if docker image exists -CMD_CHECK_IMAGE="docker images -q freqtrade:latest" -REBUILD=false -DRY_RUN=false - -while getopts rdh option -do - case "${option}" - in - r) REBUILD=true - ;; - d) DRY_RUN=true - ;; - h) cat << EOF - -Commands available : - --r Rebuild the container --d Dry Run --h This help message -EOF - exit 0 - ;; - esac -done - -# Ensures files exists -[ -d ~/.freqtrade ] || mkdir ~/.freqtrade -cp config.json ~/.freqtrade/ -touch ~/.freqtrade/tradesv2.sqlite -touch ~/.freqtrade/tradesv2.dry_run.sqlite - - -echo 'Stopping container...' -docker stop freqtrade > /dev/null \ - && docker rm freqtrade > /dev/null \ - && echo 'Container stopped' - - -if [[ -z $($CMD_CHECK_IMAGE) || $REBUILD = true ]]; then - echo "Building container" - docker build -t freqtrade . -fi - - -# Generates Docker commands based on options -DOCKER_CMD="docker run -d \ - --name freqtrade \ - -v ~/.freqtrade/config.json:/freqtrade/config.json" - -if [[ $DRY_RUN = true ]]; then - DOCKER_CMD="$DOCKER_CMD \ - -v ~/.freqtrade/tradesv2.dry_run.sqlite:/freqtrade/tradesv2.dry_run.sqlite" -else - DOCKER_CMD="$DOCKER_CMD \ - -v ~/.freqtrade/tradesv2.sqlite:/freqtrade/tradesv2.sqlite" -fi - -DOCKER_CMD="$DOCKER_CMD freqtrade" - -echo 'Starting container' -eval $DOCKER_CMD \ > /dev/null \ - && echo 'Container ready' \ - || echo 'Problem starting container' - -exit 0 - -docker run -d \ - --name freqtrade \ - -v ~/.freqtrade/config.json:/freqtrade/config.json \ - -v ~/.freqtrade/tradesv2.dry_run.sqlite:/freqtrade/tradesv2.dry_run.sqlite \ - freqtrade diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index ecac558c9..94449fa70 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -1,6 +1,8 @@ import logging from datetime import timedelta from typing import Callable, Any +from pandas import DataFrame +from tabulate import tabulate import arrow from sqlalchemy import and_, func, text @@ -100,6 +102,14 @@ def _status(bot: Bot, update: Update) -> None: :param update: message update :return: None """ + + # Check if additional parameters are passed + params = update.message.text.replace('/status', '').split(' ') \ + if update.message.text else [] + if 'table' in params: + _status_table(bot, update) + return + # Fetch open trade trades = Trade.query.filter(Trade.is_open.is_(True)).all() if get_state() != State.RUNNING: @@ -145,6 +155,71 @@ def _status(bot: Bot, update: Update) -> None: send_msg(message, bot=bot) +@authorized_only +def _status_table(bot: Bot, update: Update) -> None: + """ + Handler for /status table. + Returns the current TradeThread status in table format + :param bot: telegram bot + :param update: message update + :return: None + """ + short_version = False + params = update.message.text.replace('/status', '').split(' ') + if 'short' in params: + short_version = True + + # Fetch open trade + trades = Trade.query.filter(Trade.is_open.is_(True)).all() + if get_state() != State.RUNNING: + send_msg('*Status:* `trader is not running`', bot=bot) + elif not trades: + send_msg('*Status:* `no active order`', bot=bot) + else: + trades_list = [] + for trade in trades: + # calculate profit and send message to user + current_rate = exchange.get_ticker(trade.pair)['bid'] + current_profit = 100 * ((current_rate - trade.open_rate) / trade.open_rate) + orders = exchange.get_open_orders(trade.pair) + orders = [o for o in orders if o['id'] == trade.open_order_id] + order = orders[0] if orders else None + + fmt_close_profit = '{:.2f}'.format(trade.close_profit) if trade.close_profit else 'No' + fmt_current_profit = '{:.2f}'.format(current_profit) + + row = [ + trade.id, + trade.pair, + shorten_date(arrow.get(trade.open_date).humanize()), + round(trade.amount, 8), + trade.open_rate, + trade.close_rate, + current_rate, + fmt_close_profit, + fmt_current_profit, + '{} ({})'.format(order['remaining'], order['type']) if order else 'No' + ] + + trades_list.append(row) + + columns = ['ID', 'Pair', 'Since', 'Amount', 'Open Rate', + 'Close Rate', 'Cur. Rate', 'Close Profit', 'Profit', + 'Open Order'] + + df = DataFrame.from_records(trades_list, columns=columns) + df = df.set_index(columns[0]) + + columns_short = ['Pair', 'Since', 'Profit'] + + if short_version == True: + df = df[columns_short] + + message = tabulate(df, headers='keys', tablefmt='simple') + message = "
{}
".format(message) + + send_msg(message, parse_mode=ParseMode.HTML) + @authorized_only def _profit(bot: Bot, update: Update) -> None: """ @@ -346,15 +421,32 @@ def _help(bot: Bot, update: Update) -> None: message = """ */start:* `Starts the trader` */stop:* `Stops the trader` -*/status:* `Lists all open trades` +*/status [table [short]]:* `Lists all open trades` + *table :* `will display trades in a table` + *short :* `condensed output` */profit:* `Lists cumulative profit from all finished trades` */forcesell :* `Instantly sells the given trade, regardless of profit` */performance:* `Show performance of each finished trade grouped by pair` +*/count:* `Show number of trades running compared to allowed number of trades` */help:* `This help message` """ send_msg(message, bot=bot) +def shorten_date(date): + return date.replace('ago', '') \ + .replace('seconds', 's') \ + .replace('minutes', 'm') \ + .replace('minute', 'm') \ + .replace('hours', 'h') \ + .replace('hour', 'h') \ + .replace('days', 'd') \ + .replace('day', 'd') \ + .replace('an', '1') \ + .replace('a', '1') \ + .replace(' ', '') + + def send_msg(msg: str, bot: Bot = None, parse_mode: ParseMode = ParseMode.MARKDOWN) -> None: """ Send given markdown message diff --git a/requirements.txt b/requirements.txt index 69379b025..83292154e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,7 +17,8 @@ pytest-cov==2.5.1 hyperopt==0.1 # do not upgrade networkx before this is fixed https://github.com/hyperopt/hyperopt/issues/325 networkx==1.11 +tabulate==0.8.1 # Required for plotting data #matplotlib==2.1.0 -#PYQT5==5.9 \ No newline at end of file +#PYQT5==5.9