implement /performance command

This commit is contained in:
gcarq 2017-06-08 22:52:38 +02:00
parent 53e71e09f7
commit 0fc46378fc
2 changed files with 65 additions and 21 deletions

View File

@ -25,7 +25,7 @@ from utils import get_conf
__author__ = "gcarq" __author__ = "gcarq"
__copyright__ = "gcarq 2017" __copyright__ = "gcarq 2017"
__license__ = "GPLv3" __license__ = "GPLv3"
__version__ = "0.7.0" __version__ = "0.8.0"
conf = get_conf() conf = get_conf()
@ -131,6 +131,7 @@ def close_trade_if_fulfilled(trade):
# we can close this trade. # we can close this trade.
if trade.close_profit and trade.close_date and trade.close_rate and not trade.open_order_id: if trade.close_profit and trade.close_date and trade.close_rate and not trade.open_order_id:
trade.is_open = False trade.is_open = False
Session.flush()
return True return True
return False return False

View File

@ -2,7 +2,7 @@ import logging
from datetime import timedelta from datetime import timedelta
import arrow import arrow
from sqlalchemy import and_ from sqlalchemy import and_, func
from telegram.error import NetworkError from telegram.error import NetworkError
from telegram.ext import CommandHandler, Updater from telegram.ext import CommandHandler, Updater
from telegram import ParseMode, Bot, Update from telegram import ParseMode, Bot, Update
@ -105,31 +105,46 @@ class TelegramHandler(object):
:param update: message update :param update: message update
:return: None :return: None
""" """
trades = Trade.query.filter(Trade.is_open.is_(False)).all() trades = Trade.query.order_by(Trade.id).all()
trade_count = len(trades)
profit_amount = sum((t.close_profit / 100) * t.btc_amount for t in trades) profit_amounts = []
profit = sum(t.close_profit for t in trades) profits = []
if trades: durations = []
avg_stake_amount = round(sum(t.btc_amount for t in trades) / float(trade_count), 8) for trade in trades:
else: if trade.close_date:
avg_stake_amount = None durations.append((trade.close_date - trade.open_date).total_seconds())
durations_hours = [(t.close_date - t.open_date).total_seconds() / 3600.0 for t in trades] if trade.close_profit:
avg_duration = sum(durations_hours) / float(len(durations_hours)) profit = trade.close_profit
else:
# Get current rate
current_rate = api_wrapper.get_ticker(trade.pair)['bid']
profit = 100 * ((current_rate - trade.open_rate) / trade.open_rate)
profit_amounts.append((profit / 100) * trade.btc_amount)
profits.append(profit)
bp_pair, bp_rate = Session.query(Trade.pair, func.sum(Trade.close_profit).label('profit_sum')) \
.filter(Trade.is_open.is_(False)) \
.group_by(Trade.pair) \
.order_by('profit_sum DESC') \
.first()
markdown_msg = """ markdown_msg = """
*ROI:* `{profit_btc} ({profit}%)` *ROI:* `{profit_btc} ({profit}%)`
*Trade Count:* `{trade_count}` *Trade Count:* `{trade_count}`
*First Trade completed:* `{first_trade_date}` *First Trade opened:* `{first_trade_date}`
*Latest Trade completed:* `{latest_trade_date}` *Latest Trade opened:* `{latest_trade_date}`
*Avg. Stake Amount:* `{avg_stake_amount}` *Avg. Duration:* `{avg_duration}`
*Avg. Duration:* `{avg_duration}` *Best Performing:* `{best_pair}: {best_rate}%`
""".format( """.format(
profit_btc=round(profit_amount, 8), profit_btc=round(sum(profit_amounts), 8),
profit=round(profit, 2), profit=round(sum(profits), 2),
trade_count=trade_count, trade_count=len(trades),
first_trade_date=arrow.get(trades[0].open_date).humanize(), first_trade_date=arrow.get(trades[0].open_date).humanize(),
latest_trade_date=arrow.get(trades[-1].open_date).humanize(), latest_trade_date=arrow.get(trades[-1].open_date).humanize(),
avg_stake_amount=avg_stake_amount, avg_duration=str(timedelta(seconds=sum(durations) / float(len(durations)))).split('.')[0],
avg_duration=str(timedelta(hours=avg_duration)).split('.')[0], best_pair=bp_pair,
best_rate=round(bp_rate, 2),
) )
TelegramHandler.send_msg(markdown_msg, bot=bot) TelegramHandler.send_msg(markdown_msg, bot=bot)
@ -214,6 +229,33 @@ class TelegramHandler(object):
TelegramHandler.send_msg('Invalid argument. Usage: `/forcesell <trade_id>`') TelegramHandler.send_msg('Invalid argument. Usage: `/forcesell <trade_id>`')
logger.warning('/forcesell: Invalid argument received') logger.warning('/forcesell: Invalid argument received')
@staticmethod
@authorized_only
def _performance(bot, update):
"""
Handler for /performance.
Shows a performance statistic from finished trades
:param bot: telegram bot
:param update: message update
:return: None
"""
from main import get_instance
if not get_instance().is_alive():
TelegramHandler.send_msg('`trader is not running`', bot=bot)
return
pair_rates = Session.query(Trade.pair, func.sum(Trade.close_profit).label('profit_sum')) \
.filter(Trade.is_open.is_(False)) \
.group_by(Trade.pair) \
.order_by('profit_sum DESC') \
.all()
stats = '\n'.join('{}. <code>{}\t{}%</code>'.format(i + 1, pair, round(rate, 2)) for i, (pair, rate) in enumerate(pair_rates))
message = '<b>Performance:</b>\n{}\n'.format(stats)
logger.debug(message)
TelegramHandler.send_msg(message, parse_mode=ParseMode.HTML)
@staticmethod @staticmethod
@synchronized @synchronized
def get_updater(conf): def get_updater(conf):
@ -240,6 +282,7 @@ class TelegramHandler(object):
CommandHandler('start', TelegramHandler._start), CommandHandler('start', TelegramHandler._start),
CommandHandler('stop', TelegramHandler._stop), CommandHandler('stop', TelegramHandler._stop),
CommandHandler('forcesell', TelegramHandler._forcesell), CommandHandler('forcesell', TelegramHandler._forcesell),
CommandHandler('performance', TelegramHandler._performance),
] ]
for handle in handles: for handle in handles:
TelegramHandler.get_updater(conf).dispatcher.add_handler(handle) TelegramHandler.get_updater(conf).dispatcher.add_handler(handle)