Adds options for /status command
This commit is contained in:
parent
0e1eb20781
commit
8bdace68f6
@ -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
|
|
@ -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
|
|
@ -1,6 +1,8 @@
|
|||||||
import logging
|
import logging
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from typing import Callable, Any
|
from typing import Callable, Any
|
||||||
|
from pandas import DataFrame
|
||||||
|
from tabulate import tabulate
|
||||||
|
|
||||||
import arrow
|
import arrow
|
||||||
from sqlalchemy import and_, func, text
|
from sqlalchemy import and_, func, text
|
||||||
@ -100,6 +102,14 @@ def _status(bot: Bot, update: Update) -> None:
|
|||||||
:param update: message update
|
:param update: message update
|
||||||
:return: None
|
: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
|
# Fetch open trade
|
||||||
trades = Trade.query.filter(Trade.is_open.is_(True)).all()
|
trades = Trade.query.filter(Trade.is_open.is_(True)).all()
|
||||||
if get_state() != State.RUNNING:
|
if get_state() != State.RUNNING:
|
||||||
@ -145,6 +155,71 @@ def _status(bot: Bot, update: Update) -> None:
|
|||||||
send_msg(message, bot=bot)
|
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 = "<pre>{}</pre>".format(message)
|
||||||
|
|
||||||
|
send_msg(message, parse_mode=ParseMode.HTML)
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _profit(bot: Bot, update: Update) -> None:
|
def _profit(bot: Bot, update: Update) -> None:
|
||||||
"""
|
"""
|
||||||
@ -346,15 +421,32 @@ def _help(bot: Bot, update: Update) -> None:
|
|||||||
message = """
|
message = """
|
||||||
*/start:* `Starts the trader`
|
*/start:* `Starts the trader`
|
||||||
*/stop:* `Stops 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`
|
*/profit:* `Lists cumulative profit from all finished trades`
|
||||||
*/forcesell <trade_id>:* `Instantly sells the given trade, regardless of profit`
|
*/forcesell <trade_id>:* `Instantly sells the given trade, regardless of profit`
|
||||||
*/performance:* `Show performance of each finished trade grouped by pair`
|
*/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`
|
*/help:* `This help message`
|
||||||
"""
|
"""
|
||||||
send_msg(message, bot=bot)
|
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:
|
def send_msg(msg: str, bot: Bot = None, parse_mode: ParseMode = ParseMode.MARKDOWN) -> None:
|
||||||
"""
|
"""
|
||||||
Send given markdown message
|
Send given markdown message
|
||||||
|
@ -17,6 +17,7 @@ pytest-cov==2.5.1
|
|||||||
hyperopt==0.1
|
hyperopt==0.1
|
||||||
# do not upgrade networkx before this is fixed https://github.com/hyperopt/hyperopt/issues/325
|
# do not upgrade networkx before this is fixed https://github.com/hyperopt/hyperopt/issues/325
|
||||||
networkx==1.11
|
networkx==1.11
|
||||||
|
tabulate==0.8.1
|
||||||
|
|
||||||
# Required for plotting data
|
# Required for plotting data
|
||||||
#matplotlib==2.1.0
|
#matplotlib==2.1.0
|
||||||
|
Loading…
Reference in New Issue
Block a user