telegram refactor 3/
move out rpc_daily_profit
This commit is contained in:
parent
a70da513e8
commit
112913531c
@ -1,11 +1,13 @@
|
|||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
import arrow
|
import arrow
|
||||||
|
from datetime import datetime, timedelta
|
||||||
from pandas import DataFrame
|
from pandas import DataFrame
|
||||||
|
|
||||||
from freqtrade.persistence import Trade
|
from freqtrade.persistence import Trade
|
||||||
from freqtrade.misc import State, get_state
|
from freqtrade.misc import State, get_state
|
||||||
from freqtrade import exchange
|
from freqtrade import exchange
|
||||||
|
from freqtrade.fiat_convert import CryptoToFiatConverter
|
||||||
from . import telegram
|
from . import telegram
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -142,3 +144,41 @@ def rpc_status_table():
|
|||||||
# Another approach would be to just return the
|
# Another approach would be to just return the
|
||||||
# result, or raise error
|
# result, or raise error
|
||||||
return (False, df_statuses)
|
return (False, df_statuses)
|
||||||
|
|
||||||
|
|
||||||
|
def rpc_daily_profit(timescale, stake_currency, fiat_display_currency):
|
||||||
|
today = datetime.utcnow().date()
|
||||||
|
profit_days = {}
|
||||||
|
|
||||||
|
if not (isinstance(timescale, int) and timescale > 0):
|
||||||
|
return (True, '*Daily [n]:* `must be an integer greater than 0`')
|
||||||
|
|
||||||
|
# FIX: we might not want to call CryptoToFiatConverter, for every call
|
||||||
|
fiat = CryptoToFiatConverter()
|
||||||
|
for day in range(0, timescale):
|
||||||
|
profitday = today - timedelta(days=day)
|
||||||
|
trades = Trade.query \
|
||||||
|
.filter(Trade.is_open.is_(False)) \
|
||||||
|
.filter(Trade.close_date >= profitday)\
|
||||||
|
.filter(Trade.close_date < (profitday + timedelta(days=1)))\
|
||||||
|
.order_by(Trade.close_date)\
|
||||||
|
.all()
|
||||||
|
curdayprofit = sum(trade.calc_profit() for trade in trades)
|
||||||
|
profit_days[profitday] = format(curdayprofit, '.8f')
|
||||||
|
|
||||||
|
stats = [
|
||||||
|
[
|
||||||
|
key,
|
||||||
|
'{value:.8f} {symbol}'.format(value=float(value), symbol=stake_currency),
|
||||||
|
'{value:.3f} {symbol}'.format(
|
||||||
|
value=fiat.convert_amount(
|
||||||
|
value,
|
||||||
|
stake_currency,
|
||||||
|
fiat_display_currency
|
||||||
|
),
|
||||||
|
symbol=fiat_display_currency
|
||||||
|
)
|
||||||
|
]
|
||||||
|
for key, value in profit_days.items()
|
||||||
|
]
|
||||||
|
return (False, stats)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import logging
|
import logging
|
||||||
from datetime import datetime, timedelta
|
from datetime import timedelta
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from typing import Any, Callable
|
from typing import Any, Callable
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ from telegram import Bot, ParseMode, ReplyKeyboardMarkup, Update
|
|||||||
from telegram.error import NetworkError, TelegramError
|
from telegram.error import NetworkError, TelegramError
|
||||||
from telegram.ext import CommandHandler, Updater
|
from telegram.ext import CommandHandler, Updater
|
||||||
|
|
||||||
from freqtrade.rpc.__init__ import rpc_status_table, rpc_trade_status
|
from freqtrade.rpc.__init__ import rpc_status_table, rpc_trade_status, rpc_daily_profit
|
||||||
from freqtrade import __version__, exchange
|
from freqtrade import __version__, exchange
|
||||||
from freqtrade.fiat_convert import CryptoToFiatConverter
|
from freqtrade.fiat_convert import CryptoToFiatConverter
|
||||||
from freqtrade.misc import State, get_state, update_state
|
from freqtrade.misc import State, get_state, update_state
|
||||||
@ -166,54 +166,26 @@ def _daily(bot: Bot, update: Update) -> None:
|
|||||||
:param update: message update
|
:param update: message update
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
today = datetime.utcnow().date()
|
|
||||||
profit_days = {}
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
timescale = int(update.message.text.replace('/daily', '').strip())
|
timescale = int(update.message.text.replace('/daily', '').strip())
|
||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
timescale = 7
|
timescale = 7
|
||||||
|
(error, stats) = rpc_daily_profit(timescale,
|
||||||
if not (isinstance(timescale, int) and timescale > 0):
|
_CONF['stake_currency'],
|
||||||
send_msg('*Daily [n]:* `must be an integer greater than 0`', bot=bot)
|
_CONF['fiat_display_currency'])
|
||||||
return
|
if error:
|
||||||
|
send_msg(stats, bot=bot)
|
||||||
for day in range(0, timescale):
|
else:
|
||||||
profitday = today - timedelta(days=day)
|
stats = tabulate(stats,
|
||||||
trades = Trade.query \
|
headers=[
|
||||||
.filter(Trade.is_open.is_(False)) \
|
'Day',
|
||||||
.filter(Trade.close_date >= profitday)\
|
'Profit {}'.format(_CONF['stake_currency']),
|
||||||
.filter(Trade.close_date < (profitday + timedelta(days=1)))\
|
'Profit {}'.format(_CONF['fiat_display_currency'])
|
||||||
.order_by(Trade.close_date)\
|
],
|
||||||
.all()
|
tablefmt='simple')
|
||||||
curdayprofit = sum(trade.calc_profit() for trade in trades)
|
message = '<b>Daily Profit over the last {} days</b>:\n<pre>{}</pre>'.format(
|
||||||
profit_days[profitday] = format(curdayprofit, '.8f')
|
timescale, stats)
|
||||||
|
send_msg(message, bot=bot, parse_mode=ParseMode.HTML)
|
||||||
stats = [
|
|
||||||
[
|
|
||||||
key,
|
|
||||||
'{value:.8f} {symbol}'.format(value=float(value), symbol=_CONF['stake_currency']),
|
|
||||||
'{value:.3f} {symbol}'.format(
|
|
||||||
value=_FIAT_CONVERT.convert_amount(
|
|
||||||
value,
|
|
||||||
_CONF['stake_currency'],
|
|
||||||
_CONF['fiat_display_currency']
|
|
||||||
),
|
|
||||||
symbol=_CONF['fiat_display_currency']
|
|
||||||
)
|
|
||||||
]
|
|
||||||
for key, value in profit_days.items()
|
|
||||||
]
|
|
||||||
stats = tabulate(stats,
|
|
||||||
headers=[
|
|
||||||
'Day',
|
|
||||||
'Profit {}'.format(_CONF['stake_currency']),
|
|
||||||
'Profit {}'.format(_CONF['fiat_display_currency'])
|
|
||||||
],
|
|
||||||
tablefmt='simple')
|
|
||||||
|
|
||||||
message = '<b>Daily Profit over the last {} days</b>:\n<pre>{}</pre>'.format(timescale, stats)
|
|
||||||
send_msg(message, bot=bot, parse_mode=ParseMode.HTML)
|
|
||||||
|
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
# pragma pylint: disable=missing-docstring, too-many-arguments, too-many-ancestors, C0103
|
# pragma pylint: disable=missing-docstring, too-many-arguments, too-many-ancestors, C0103
|
||||||
|
from datetime import datetime
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
from sqlalchemy import create_engine
|
||||||
|
|
||||||
from freqtrade.rpc import init, cleanup, send_msg
|
from freqtrade.rpc import init, cleanup, send_msg
|
||||||
from sqlalchemy import create_engine
|
from freqtrade.persistence import Trade
|
||||||
import freqtrade.main as main
|
import freqtrade.main as main
|
||||||
import freqtrade.misc as misc
|
import freqtrade.misc as misc
|
||||||
import freqtrade.rpc as rpc
|
import freqtrade.rpc as rpc
|
||||||
@ -88,3 +90,55 @@ def test_rpc_trade_status(default_conf, update, ticker, mocker):
|
|||||||
assert not error
|
assert not error
|
||||||
trade = result[0]
|
trade = result[0]
|
||||||
assert trade.find('[BTC_ETH]') >= 0
|
assert trade.find('[BTC_ETH]') >= 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_rpc_daily_profit(default_conf, update, ticker, limit_buy_order, limit_sell_order, mocker):
|
||||||
|
mocker.patch.dict('freqtrade.main._CONF', default_conf)
|
||||||
|
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: True)
|
||||||
|
mocker.patch('freqtrade.main.rpc.send_msg', MagicMock())
|
||||||
|
mocker.patch.multiple('freqtrade.rpc.telegram',
|
||||||
|
_CONF=default_conf,
|
||||||
|
init=MagicMock())
|
||||||
|
mocker.patch.multiple('freqtrade.main.exchange',
|
||||||
|
validate_pairs=MagicMock(),
|
||||||
|
get_ticker=ticker)
|
||||||
|
mocker.patch.multiple('freqtrade.fiat_convert.Pymarketcap',
|
||||||
|
ticker=MagicMock(return_value={'price_usd': 15000.0}),
|
||||||
|
_cache_symbols=MagicMock(return_value={'BTC': 1}))
|
||||||
|
mocker.patch('freqtrade.fiat_convert.CryptoToFiatConverter._find_price', return_value=15000.0)
|
||||||
|
main.init(default_conf, create_engine('sqlite://'))
|
||||||
|
stake_currency = default_conf['stake_currency']
|
||||||
|
fiat_display_currency = default_conf['fiat_display_currency']
|
||||||
|
|
||||||
|
# Create some test data
|
||||||
|
main.create_trade(0.001)
|
||||||
|
trade = Trade.query.first()
|
||||||
|
assert trade
|
||||||
|
|
||||||
|
# Simulate buy & sell
|
||||||
|
trade.update(limit_buy_order)
|
||||||
|
trade.update(limit_sell_order)
|
||||||
|
trade.close_date = datetime.utcnow()
|
||||||
|
trade.is_open = False
|
||||||
|
|
||||||
|
# Try valid data
|
||||||
|
update.message.text = '/daily 2'
|
||||||
|
(error, days) = rpc.rpc_daily_profit(7, stake_currency,
|
||||||
|
fiat_display_currency)
|
||||||
|
assert not error
|
||||||
|
assert len(days) == 7
|
||||||
|
for day in days:
|
||||||
|
# [datetime.date(2018, 1, 11), '0.00000000 BTC', '0.000 USD']
|
||||||
|
assert (day[1] == '0.00000000 BTC' or
|
||||||
|
day[1] == '0.00006217 BTC')
|
||||||
|
|
||||||
|
assert (day[2] == '0.000 USD' or
|
||||||
|
day[2] == '0.933 USD')
|
||||||
|
# ensure first day is current date
|
||||||
|
assert str(days[0][0]) == str(datetime.utcnow().date())
|
||||||
|
|
||||||
|
# Try invalid data
|
||||||
|
(error, days) = rpc.rpc_daily_profit(0, stake_currency,
|
||||||
|
fiat_display_currency)
|
||||||
|
assert error
|
||||||
|
assert days.find('must be an integer greater than 0') >= 0
|
||||||
|
Loading…
Reference in New Issue
Block a user