From 9467461160907f4b96252a8d60520cf2c911d069 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 21 Jul 2018 20:13:32 +0200 Subject: [PATCH 01/19] only init FIATConvert when telegram is enabled --- freqtrade/freqtradebot.py | 16 ---------------- freqtrade/rpc/telegram.py | 7 +++++++ freqtrade/tests/test_main.py | 5 ----- 3 files changed, 7 insertions(+), 21 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 35c0a1705..4296334f1 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -16,7 +16,6 @@ from cachetools import TTLCache, cached from freqtrade import (DependencyException, OperationalException, TemporaryError, __version__, constants, persistence) from freqtrade.exchange import Exchange -from freqtrade.fiat_convert import CryptoToFiatConverter from freqtrade.persistence import Trade from freqtrade.rpc import RPCManager, RPCMessageType from freqtrade.state import State @@ -49,7 +48,6 @@ class FreqtradeBot(object): # Init objects self.config = config self.strategy: IStrategy = StrategyResolver(self.config).strategy - self.fiat_converter = CryptoToFiatConverter() self.rpc: RPCManager = RPCManager(self) self.persistence = None self.exchange = Exchange(self.config) @@ -363,12 +361,6 @@ class FreqtradeBot(object): order_id = self.exchange.buy(pair, buy_limit, amount)['id'] - stake_amount_fiat = self.fiat_converter.convert_amount( - stake_amount, - stake_currency, - fiat_currency - ) - self.rpc.send_msg({ 'type': RPCMessageType.BUY_NOTIFICATION, 'exchange': self.exchange.name.capitalize(), @@ -376,7 +368,6 @@ class FreqtradeBot(object): 'market_url': pair_url, 'limit': buy_limit, 'stake_amount': stake_amount, - 'stake_amount_fiat': stake_amount_fiat, 'stake_currency': stake_currency, 'fiat_currency': fiat_currency }) @@ -643,14 +634,7 @@ class FreqtradeBot(object): if 'stake_currency' in self.config and 'fiat_display_currency' in self.config: stake_currency = self.config['stake_currency'] fiat_currency = self.config['fiat_display_currency'] - fiat_converter = CryptoToFiatConverter() - profit_fiat = fiat_converter.convert_amount( - profit_trade, - stake_currency, - fiat_currency, - ) msg.update({ - 'profit_fiat': profit_fiat, 'stake_currency': stake_currency, 'fiat_currency': fiat_currency, }) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 02b74358e..ea978bf8d 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -12,6 +12,7 @@ from telegram.error import NetworkError, TelegramError from telegram.ext import CommandHandler, Updater from freqtrade.__init__ import __version__ +from freqtrade.fiat_convert import CryptoToFiatConverter from freqtrade.rpc import RPC, RPCException, RPCMessageType logger = logging.getLogger(__name__) @@ -66,6 +67,7 @@ class Telegram(RPC): self._updater: Updater = None self._config = freqtrade.config self._init() + self._fiat_converter = CryptoToFiatConverter() def _init(self) -> None: """ @@ -114,6 +116,9 @@ class Telegram(RPC): """ Send a message to telegram channel """ if msg['type'] == RPCMessageType.BUY_NOTIFICATION: + msg['stake_amount_fiat'] = self._fiat_converter.convert_amount( + msg['stake_amount'], msg['stake_currency'], msg['fiat_currency']) + message = "*{exchange}:* Buying [{pair}]({market_url})\n" \ "with limit `{limit:.8f}\n" \ "({stake_amount:.6f} {stake_currency}," \ @@ -135,6 +140,8 @@ class Telegram(RPC): # This might not be the case if the message origin is triggered by /forcesell if all(prop in msg for prop in ['gain', 'profit_fiat', 'fiat_currency', 'stake_currency']): + msg['profit_fiat'] = self._fiat_converter.convert_amount( + msg['profit_amount'], msg['stake_currency'], msg['fiat_currency']) message += '` ({gain}: {profit_amount:.8f} {stake_currency}`' \ '` / {profit_fiat:.3f} {fiat_currency})`'.format(**msg) diff --git a/freqtrade/tests/test_main.py b/freqtrade/tests/test_main.py index 446945a07..80f5367b8 100644 --- a/freqtrade/tests/test_main.py +++ b/freqtrade/tests/test_main.py @@ -62,7 +62,6 @@ def test_main_fatal_exception(mocker, default_conf, caplog) -> None: 'freqtrade.configuration.Configuration._load_config_file', lambda *args, **kwargs: default_conf ) - mocker.patch('freqtrade.freqtradebot.CryptoToFiatConverter', MagicMock()) mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock()) args = ['-c', 'config.json.example'] @@ -90,7 +89,6 @@ def test_main_keyboard_interrupt(mocker, default_conf, caplog) -> None: 'freqtrade.configuration.Configuration._load_config_file', lambda *args, **kwargs: default_conf ) - mocker.patch('freqtrade.freqtradebot.CryptoToFiatConverter', MagicMock()) mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock()) args = ['-c', 'config.json.example'] @@ -118,7 +116,6 @@ def test_main_operational_exception(mocker, default_conf, caplog) -> None: 'freqtrade.configuration.Configuration._load_config_file', lambda *args, **kwargs: default_conf ) - mocker.patch('freqtrade.freqtradebot.CryptoToFiatConverter', MagicMock()) mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock()) args = ['-c', 'config.json.example'] @@ -146,7 +143,6 @@ def test_main_reload_conf(mocker, default_conf, caplog) -> None: 'freqtrade.configuration.Configuration._load_config_file', lambda *args, **kwargs: default_conf ) - mocker.patch('freqtrade.freqtradebot.CryptoToFiatConverter', MagicMock()) mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock()) # Raise exception as side effect to avoid endless loop @@ -174,7 +170,6 @@ def test_reconfigure(mocker, default_conf) -> None: 'freqtrade.configuration.Configuration._load_config_file', lambda *args, **kwargs: default_conf ) - mocker.patch('freqtrade.freqtradebot.CryptoToFiatConverter', MagicMock()) mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock()) freqtrade = FreqtradeBot(default_conf) From be3f04775ae476c406b733efafb66c96d801a513 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 21 Jul 2018 20:21:00 +0200 Subject: [PATCH 02/19] remove unnecessary mocks - add mocks which went to exchange --- freqtrade/tests/test_freqtradebot.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index b7ae96048..b5223b4b3 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -1352,7 +1352,6 @@ def test_execute_sell_up(default_conf, ticker, fee, ticker_sell_up, markets, moc get_fee=fee, get_markets=markets ) - mocker.patch('freqtrade.fiat_convert.CryptoToFiatConverter._find_price', return_value=15000.0) freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) @@ -1385,7 +1384,6 @@ def test_execute_sell_up(default_conf, ticker, fee, ticker_sell_up, markets, moc 'current_rate': 1.172e-05, 'profit_amount': 6.126e-05, 'profit_percent': 0.06110514, - 'profit_fiat': 0.9189, 'stake_currency': 'BTC', 'fiat_currency': 'USD', } == last_msg @@ -1397,7 +1395,6 @@ def test_execute_sell_down(default_conf, ticker, fee, ticker_sell_down, markets, """ rpc_mock = patch_RPCManager(mocker) patch_coinmarketcap(mocker) - mocker.patch('freqtrade.fiat_convert.CryptoToFiatConverter._find_price', return_value=15000.0) mocker.patch.multiple( 'freqtrade.exchange.Exchange', validate_pairs=MagicMock(), @@ -1437,7 +1434,6 @@ def test_execute_sell_down(default_conf, ticker, fee, ticker_sell_down, markets, 'current_rate': 1.044e-05, 'profit_amount': -5.492e-05, 'profit_percent': -0.05478343, - 'profit_fiat': -0.8238000000000001, 'stake_currency': 'BTC', 'fiat_currency': 'USD', } == last_msg @@ -1726,7 +1722,7 @@ def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order, fee, markets, m assert freqtrade.handle_trade(trade) is True -def test_trailing_stop_loss(default_conf, limit_buy_order, fee, caplog, mocker) -> None: +def test_trailing_stop_loss(default_conf, limit_buy_order, fee, markets, caplog, mocker) -> None: """ Test sell_profit_only feature when enabled and we have a loss """ @@ -1742,6 +1738,7 @@ def test_trailing_stop_loss(default_conf, limit_buy_order, fee, caplog, mocker) }), buy=MagicMock(return_value={'id': limit_buy_order['id']}), get_fee=fee, + get_markets=markets, ) conf = deepcopy(default_conf) @@ -1763,7 +1760,8 @@ def test_trailing_stop_loss(default_conf, limit_buy_order, fee, caplog, mocker) f'initial stop loss was at 0.000010, trade opened at 0.000011', caplog.record_tuples) -def test_trailing_stop_loss_positive(default_conf, limit_buy_order, fee, caplog, mocker) -> None: +def test_trailing_stop_loss_positive(default_conf, limit_buy_order, fee, markets, + caplog, mocker) -> None: """ Test sell_profit_only feature when enabled and we have a loss """ @@ -1780,6 +1778,7 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order, fee, caplog, }), buy=MagicMock(return_value={'id': limit_buy_order['id']}), get_fee=fee, + get_markets=markets, ) conf = deepcopy(default_conf) From 0681a806cc934c974ad5b9c0842cd368edc80697 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 21 Jul 2018 20:44:38 +0200 Subject: [PATCH 03/19] move cryptofiatconvert to rpc --- freqtrade/rpc/rpc.py | 24 +++++++++++++++--------- freqtrade/tests/rpc/test_rpc.py | 9 ++++++--- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 9411e983b..0e643b734 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -13,8 +13,10 @@ import sqlalchemy as sql from numpy import mean, nan_to_num from pandas import DataFrame +from freqtrade.fiat_convert import CryptoToFiatConverter from freqtrade.misc import shorten_date from freqtrade.persistence import Trade + from freqtrade.state import State logger = logging.getLogger(__name__) @@ -48,6 +50,9 @@ class RPC(object): """ RPC class can be used to have extra feature, like bot data, and access to DB data """ + # Initialize _fiat_converter if needed in each RPC handler + _fiat_converter: CryptoToFiatConverter = None + def __init__(self, freqtrade) -> None: """ Initializes all enabled rpc modules @@ -141,7 +146,7 @@ class RPC(object): if not (isinstance(timescale, int) and timescale > 0): raise RPCException('timescale must be an integer greater than 0') - fiat = self._freqtrade.fiat_converter + fiat = self._fiat_converter for day in range(0, timescale): profitday = today - timedelta(days=day) trades = Trade.query \ @@ -168,7 +173,7 @@ class RPC(object): value['amount'], stake_currency, fiat_display_currency - ), + ) if self._fiat_converter else 0, symbol=fiat_display_currency ), '{value} trade{s}'.format( @@ -225,22 +230,23 @@ class RPC(object): # FIX: we want to keep fiatconverter in a state/environment, # doing this will utilize its caching functionallity, instead we reinitialize it here - fiat = self._freqtrade.fiat_converter # Prepare data to display profit_closed_coin_sum = round(sum(profit_closed_coin), 8) profit_closed_percent = round(nan_to_num(mean(profit_closed_percent)) * 100, 2) - profit_closed_fiat = fiat.convert_amount( + profit_closed_fiat = self._fiat_converter.convert_amount( profit_closed_coin_sum, stake_currency, fiat_display_currency - ) + ) if self._fiat_converter else 0 + profit_all_coin_sum = round(sum(profit_all_coin), 8) profit_all_percent = round(nan_to_num(mean(profit_all_percent)) * 100, 2) - profit_all_fiat = fiat.convert_amount( + profit_all_fiat = self._fiat_converter.convert_amount( profit_all_coin_sum, stake_currency, fiat_display_currency - ) + ) if self._fiat_converter else 0 + num = float(len(durations) or 1) return { 'profit_closed_coin': profit_closed_coin_sum, @@ -284,9 +290,9 @@ class RPC(object): if total == 0.0: raise RPCException('all balances are zero') - fiat = self._freqtrade.fiat_converter symbol = fiat_display_currency - value = fiat.convert_amount(total, 'BTC', symbol) + value = self._fiat_converter.convert_amount(total, 'BTC', + symbol) if self._fiat_converter else 0 return { 'currencies': output, 'total': total, diff --git a/freqtrade/tests/rpc/test_rpc.py b/freqtrade/tests/rpc/test_rpc.py index e6cfceae7..e3530a149 100644 --- a/freqtrade/tests/rpc/test_rpc.py +++ b/freqtrade/tests/rpc/test_rpc.py @@ -9,6 +9,7 @@ from unittest.mock import MagicMock, ANY import pytest +from freqtrade.fiat_convert import CryptoToFiatConverter from freqtrade.freqtradebot import FreqtradeBot from freqtrade.persistence import Trade from freqtrade.rpc import RPC, RPCException @@ -124,7 +125,7 @@ def test_rpc_daily_profit(default_conf, update, ticker, fee, fiat_display_currency = default_conf['fiat_display_currency'] rpc = RPC(freqtradebot) - + rpc._fiat_converter = CryptoToFiatConverter() # Create some test data freqtradebot.create_trade() trade = Trade.query.first() @@ -164,7 +165,7 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee, 'freqtrade.fiat_convert.Market', ticker=MagicMock(return_value={'price_usd': 15000.0}), ) - mocker.patch('freqtrade.fiat_convert.CryptoToFiatConverter._find_price', return_value=15000.0) + mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch.multiple( 'freqtrade.exchange.Exchange', @@ -180,6 +181,7 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee, fiat_display_currency = default_conf['fiat_display_currency'] rpc = RPC(freqtradebot) + rpc._fiat_converter = CryptoToFiatConverter() with pytest.raises(RPCException, match=r'.*no closed trade*'): rpc._rpc_trade_statistics(stake_currency, fiat_display_currency) @@ -313,7 +315,7 @@ def test_rpc_balance_handle(default_conf, mocker): 'freqtrade.fiat_convert.Market', ticker=MagicMock(return_value={'price_usd': 15000.0}), ) - mocker.patch('freqtrade.fiat_convert.CryptoToFiatConverter._find_price', return_value=15000.0) + mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch.multiple( 'freqtrade.exchange.Exchange', @@ -324,6 +326,7 @@ def test_rpc_balance_handle(default_conf, mocker): freqtradebot = FreqtradeBot(default_conf) patch_get_signal(freqtradebot, (True, False)) rpc = RPC(freqtradebot) + rpc._fiat_converter = CryptoToFiatConverter() result = rpc._rpc_balance(default_conf['fiat_display_currency']) assert prec_satoshi(result['total'], 12) From f297d22edbc202d34a3e388979a705bfeff00086 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 21 Jul 2018 20:49:57 +0200 Subject: [PATCH 04/19] fix some tests in rpc_telegram --- freqtrade/tests/rpc/test_rpc_telegram.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py index 3336810bd..61cf52839 100644 --- a/freqtrade/tests/rpc/test_rpc_telegram.py +++ b/freqtrade/tests/rpc/test_rpc_telegram.py @@ -17,6 +17,7 @@ from telegram import Chat, Message, Update from telegram.error import NetworkError from freqtrade import __version__ +from freqtrade.fiat_convert import CryptoToFiatConverter from freqtrade.freqtradebot import FreqtradeBot from freqtrade.persistence import Trade from freqtrade.rpc import RPCMessageType @@ -362,7 +363,7 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee, """ patch_coinmarketcap(mocker, value={'price_usd': 15000.0}) mocker.patch( - 'freqtrade.fiat_convert.CryptoToFiatConverter._find_price', + 'freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0 ) mocker.patch.multiple( @@ -474,7 +475,7 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee, Test _profit() method """ patch_coinmarketcap(mocker, value={'price_usd': 15000.0}) - mocker.patch('freqtrade.fiat_convert.CryptoToFiatConverter._find_price', return_value=15000.0) + mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0) mocker.patch.multiple( 'freqtrade.exchange.Exchange', validate_pairs=MagicMock(), @@ -742,7 +743,7 @@ def test_forcesell_handle(default_conf, update, ticker, fee, Test _forcesell() method """ patch_coinmarketcap(mocker, value={'price_usd': 15000.0}) - mocker.patch('freqtrade.fiat_convert.CryptoToFiatConverter._find_price', return_value=15000.0) + mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0) rpc_mock = mocker.patch('freqtrade.rpc.telegram.Telegram.send_msg', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock()) mocker.patch.multiple( @@ -783,7 +784,6 @@ def test_forcesell_handle(default_conf, update, ticker, fee, 'current_rate': 1.172e-05, 'profit_amount': 6.126e-05, 'profit_percent': 0.06110514, - 'profit_fiat': 0.9189, 'stake_currency': 'BTC', 'fiat_currency': 'USD', } == last_msg @@ -1134,7 +1134,6 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None: 'current_rate': 3.201e-05, 'profit_amount': -0.05746268, 'profit_percent': -0.57405275, - 'profit_fiat': -24.81204044792, 'stake_currency': 'ETH', 'fiat_currency': 'USD' }) From 6cc0a72bcad370ad9aea0bff9ed84666485636d3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 22 Jul 2018 14:35:29 +0200 Subject: [PATCH 05/19] ADd optional to class _fiat_convert --- freqtrade/rpc/rpc.py | 7 +++---- freqtrade/rpc/telegram.py | 11 +++++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 0e643b734..1fc99fd98 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -6,7 +6,7 @@ from abc import abstractmethod from datetime import timedelta, datetime, date from decimal import Decimal from enum import Enum -from typing import Dict, Any, List +from typing import Dict, Any, List, Optional import arrow import sqlalchemy as sql @@ -51,7 +51,7 @@ class RPC(object): RPC class can be used to have extra feature, like bot data, and access to DB data """ # Initialize _fiat_converter if needed in each RPC handler - _fiat_converter: CryptoToFiatConverter = None + _fiat_converter: Optional[CryptoToFiatConverter] = None def __init__(self, freqtrade) -> None: """ @@ -146,7 +146,6 @@ class RPC(object): if not (isinstance(timescale, int) and timescale > 0): raise RPCException('timescale must be an integer greater than 0') - fiat = self._fiat_converter for day in range(0, timescale): profitday = today - timedelta(days=day) trades = Trade.query \ @@ -169,7 +168,7 @@ class RPC(object): symbol=stake_currency ), '{value:.3f} {symbol}'.format( - value=fiat.convert_amount( + value=self._fiat_converter.convert_amount( value['amount'], stake_currency, fiat_display_currency diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index ea978bf8d..61f5863df 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -116,8 +116,11 @@ class Telegram(RPC): """ Send a message to telegram channel """ if msg['type'] == RPCMessageType.BUY_NOTIFICATION: - msg['stake_amount_fiat'] = self._fiat_converter.convert_amount( - msg['stake_amount'], msg['stake_currency'], msg['fiat_currency']) + if self._fiat_converter: + msg['stake_amount_fiat'] = self._fiat_converter.convert_amount( + msg['stake_amount'], msg['stake_currency'], msg['fiat_currency']) + else: + msg['stake_amount_fiat'] = 0 message = "*{exchange}:* Buying [{pair}]({market_url})\n" \ "with limit `{limit:.8f}\n" \ @@ -138,8 +141,8 @@ class Telegram(RPC): # Check if all sell properties are available. # This might not be the case if the message origin is triggered by /forcesell - if all(prop in msg for prop in ['gain', 'profit_fiat', - 'fiat_currency', 'stake_currency']): + if (all(prop in msg for prop in ['gain', 'fiat_currency', 'stake_currency']) + and self._fiat_converter): msg['profit_fiat'] = self._fiat_converter.convert_amount( msg['profit_amount'], msg['stake_currency'], msg['fiat_currency']) message += '` ({gain}: {profit_amount:.8f} {stake_currency}`' \ From 2b297869a10be08ae0add38d5f75d986b984052c Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 22 Jul 2018 14:35:59 +0200 Subject: [PATCH 06/19] adjust checks to fit new functionality --- freqtrade/tests/rpc/test_rpc_telegram.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py index 61cf52839..b7b20ff92 100644 --- a/freqtrade/tests/rpc/test_rpc_telegram.py +++ b/freqtrade/tests/rpc/test_rpc_telegram.py @@ -17,7 +17,6 @@ from telegram import Chat, Message, Update from telegram.error import NetworkError from freqtrade import __version__ -from freqtrade.fiat_convert import CryptoToFiatConverter from freqtrade.freqtradebot import FreqtradeBot from freqtrade.persistence import Trade from freqtrade.rpc import RPCMessageType @@ -841,7 +840,6 @@ def test_forcesell_down_handle(default_conf, update, ticker, fee, 'current_rate': 1.044e-05, 'profit_amount': -5.492e-05, 'profit_percent': -0.05478343, - 'profit_fiat': -0.8238000000000001, 'stake_currency': 'BTC', 'fiat_currency': 'USD', } == last_msg @@ -890,7 +888,6 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, markets, mocker 'current_rate': 1.098e-05, 'profit_amount': -5.91e-06, 'profit_percent': -0.00589292, - 'profit_fiat': -0.08865, 'stake_currency': 'BTC', 'fiat_currency': 'USD', } == msg @@ -1122,6 +1119,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None: ) freqtradebot = get_patched_freqtradebot(mocker, default_conf) telegram = Telegram(freqtradebot) + telegram._fiat_converter.convert_amount = lambda a, b, c: -24.812 telegram.send_msg({ 'type': RPCMessageType.SELL_NOTIFICATION, 'exchange': 'Binance', From fae4c3a4e3e45a7d9c803d509fb806347e9322da Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 22 Jul 2018 14:48:06 +0200 Subject: [PATCH 07/19] only init if stake_currency is set --- freqtrade/rpc/telegram.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 61f5863df..c01aa2701 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -67,7 +67,8 @@ class Telegram(RPC): self._updater: Updater = None self._config = freqtrade.config self._init() - self._fiat_converter = CryptoToFiatConverter() + if self._config.get('stake_currency', None): + self._fiat_converter = CryptoToFiatConverter() def _init(self) -> None: """ From 4d864df59ed856599a64f230425bbb1683c2c4c8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 22 Jul 2018 14:49:07 +0200 Subject: [PATCH 08/19] Add tests for no_fiat functionality --- freqtrade/tests/rpc/test_rpc_telegram.py | 62 ++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py index b7b20ff92..b82268a7b 100644 --- a/freqtrade/tests/rpc/test_rpc_telegram.py +++ b/freqtrade/tests/rpc/test_rpc_telegram.py @@ -1200,6 +1200,68 @@ def test_send_msg_unknown_type(default_conf, mocker) -> None: }) +def test_send_msg_buy_notification_no_fiat(default_conf, mocker) -> None: + del default_conf['stake_currency'] + msg_mock = MagicMock() + mocker.patch.multiple( + 'freqtrade.rpc.telegram.Telegram', + _init=MagicMock(), + _send_msg=msg_mock + ) + freqtradebot = get_patched_freqtradebot(mocker, default_conf) + telegram = Telegram(freqtradebot) + telegram.send_msg({ + 'type': RPCMessageType.BUY_NOTIFICATION, + 'exchange': 'Bittrex', + 'pair': 'ETH/BTC', + 'market_url': 'https://bittrex.com/Market/Index?MarketName=BTC-ETH', + 'limit': 1.099e-05, + 'stake_amount': 0.001, + 'stake_amount_fiat': 0.0, + 'stake_currency': 'BTC', + 'fiat_currency': 'USD' + }) + assert msg_mock.call_args[0][0] \ + == '*Bittrex:* Buying [ETH/BTC](https://bittrex.com/Market/Index?MarketName=BTC-ETH)\n' \ + 'with limit `0.00001099\n' \ + '(0.001000 BTC,0.000 USD)`' + + +def test_send_msg_sell_notification_no_fiat(default_conf, mocker) -> None: + del default_conf['stake_currency'] + msg_mock = MagicMock() + mocker.patch.multiple( + 'freqtrade.rpc.telegram.Telegram', + _init=MagicMock(), + _send_msg=msg_mock + ) + freqtradebot = get_patched_freqtradebot(mocker, default_conf) + telegram = Telegram(freqtradebot) + telegram.send_msg({ + 'type': RPCMessageType.SELL_NOTIFICATION, + 'exchange': 'Binance', + 'pair': 'KEY/ETH', + 'gain': 'loss', + 'market_url': 'https://www.binance.com/tradeDetail.html?symbol=KEY_ETH', + 'limit': 3.201e-05, + 'amount': 1333.3333333333335, + 'open_rate': 7.5e-05, + 'current_rate': 3.201e-05, + 'profit_amount': -0.05746268, + 'profit_percent': -0.57405275, + 'stake_currency': 'ETH', + 'fiat_currency': 'USD' + }) + assert msg_mock.call_args[0][0] \ + == '*Binance:* Selling [KEY/ETH]' \ + '(https://www.binance.com/tradeDetail.html?symbol=KEY_ETH)\n' \ + '*Limit:* `0.00003201`\n' \ + '*Amount:* `1333.33333333`\n' \ + '*Open Rate:* `0.00007500`\n' \ + '*Current Rate:* `0.00003201`\n' \ + '*Profit:* `-57.41%`' + + def test__send_msg(default_conf, mocker) -> None: """ Test send_msg() method From bd2771b8f990fa60fa9efaee7b786e821fcda656 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 22 Jul 2018 14:52:58 +0200 Subject: [PATCH 09/19] use correct property --- freqtrade/rpc/telegram.py | 2 +- freqtrade/tests/rpc/test_rpc_telegram.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index c01aa2701..166979d25 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -67,7 +67,7 @@ class Telegram(RPC): self._updater: Updater = None self._config = freqtrade.config self._init() - if self._config.get('stake_currency', None): + if self._config.get('fiat_display_currency', None): self._fiat_converter = CryptoToFiatConverter() def _init(self) -> None: diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py index b82268a7b..da4279a06 100644 --- a/freqtrade/tests/rpc/test_rpc_telegram.py +++ b/freqtrade/tests/rpc/test_rpc_telegram.py @@ -1201,7 +1201,7 @@ def test_send_msg_unknown_type(default_conf, mocker) -> None: def test_send_msg_buy_notification_no_fiat(default_conf, mocker) -> None: - del default_conf['stake_currency'] + del default_conf['fiat_display_currency'] msg_mock = MagicMock() mocker.patch.multiple( 'freqtrade.rpc.telegram.Telegram', @@ -1228,7 +1228,7 @@ def test_send_msg_buy_notification_no_fiat(default_conf, mocker) -> None: def test_send_msg_sell_notification_no_fiat(default_conf, mocker) -> None: - del default_conf['stake_currency'] + del default_conf['fiat_display_currency'] msg_mock = MagicMock() mocker.patch.multiple( 'freqtrade.rpc.telegram.Telegram', From 4c8411537f6e7e9d66686ae383d375bbf52e0495 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 22 Jul 2018 14:53:46 +0200 Subject: [PATCH 10/19] Don't require fiat-currency --- freqtrade/constants.py | 1 - 1 file changed, 1 deletion(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 385dac1d1..c27cd875c 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -153,7 +153,6 @@ CONF_SCHEMA = { 'max_open_trades', 'stake_currency', 'stake_amount', - 'fiat_display_currency', 'dry_run', 'bid_strategy', 'telegram' From f54ac5a8de6ebfdbf2d1f5b0f71f77fe5de14bb8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 22 Jul 2018 17:05:22 +0100 Subject: [PATCH 11/19] revert bugfix done in it's own branch --- freqtrade/tests/test_freqtradebot.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index b5223b4b3..e87bbc4a4 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -1722,7 +1722,7 @@ def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order, fee, markets, m assert freqtrade.handle_trade(trade) is True -def test_trailing_stop_loss(default_conf, limit_buy_order, fee, markets, caplog, mocker) -> None: +def test_trailing_stop_loss(default_conf, limit_buy_order, fee, caplog, mocker) -> None: """ Test sell_profit_only feature when enabled and we have a loss """ @@ -1738,7 +1738,6 @@ def test_trailing_stop_loss(default_conf, limit_buy_order, fee, markets, caplog, }), buy=MagicMock(return_value={'id': limit_buy_order['id']}), get_fee=fee, - get_markets=markets, ) conf = deepcopy(default_conf) @@ -1760,8 +1759,7 @@ def test_trailing_stop_loss(default_conf, limit_buy_order, fee, markets, caplog, f'initial stop loss was at 0.000010, trade opened at 0.000011', caplog.record_tuples) -def test_trailing_stop_loss_positive(default_conf, limit_buy_order, fee, markets, - caplog, mocker) -> None: +def test_trailing_stop_loss_positive(default_conf, limit_buy_order, fee, caplog, mocker) -> None: """ Test sell_profit_only feature when enabled and we have a loss """ @@ -1778,7 +1776,6 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order, fee, markets }), buy=MagicMock(return_value={'id': limit_buy_order['id']}), get_fee=fee, - get_markets=markets, ) conf = deepcopy(default_conf) From 456e49fe355b4defc9f954c70467fddc7eb8a63a Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 24 Jul 2018 00:01:51 +0100 Subject: [PATCH 12/19] default fiat_currency to none --- freqtrade/rpc/telegram.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 166979d25..a63422970 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -224,7 +224,7 @@ class Telegram(RPC): :return: None """ stake_cur = self._config['stake_currency'] - fiat_disp_cur = self._config['fiat_display_currency'] + fiat_disp_cur = self._config.get('fiat_display_currency', None) try: timescale = int(update.message.text.replace('/daily', '').strip()) except (TypeError, ValueError): @@ -257,7 +257,7 @@ class Telegram(RPC): :return: None """ stake_cur = self._config['stake_currency'] - fiat_disp_cur = self._config['fiat_display_currency'] + fiat_disp_cur = self._config.get('fiat_display_currency', None) try: stats = self._rpc_trade_statistics( @@ -296,7 +296,7 @@ class Telegram(RPC): def _balance(self, bot: Bot, update: Update) -> None: """ Handler for /balance """ try: - result = self._rpc_balance(self._config['fiat_display_currency']) + result = self._rpc_balance(self._config.get('fiat_display_currency', None)) output = '' for currency in result['currencies']: output += "*{currency}:*\n" \ From 1a9ead45ebb75f360789316e2cca7072ce790dcc Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 24 Jul 2018 08:00:56 +0100 Subject: [PATCH 13/19] fix missed fiat_display_currency config value --- freqtrade/freqtradebot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 4296334f1..25c6ece0d 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -344,7 +344,7 @@ class FreqtradeBot(object): pair_s = pair.replace('_', '/') pair_url = self.exchange.get_pair_detail_url(pair) stake_currency = self.config['stake_currency'] - fiat_currency = self.config['fiat_display_currency'] + fiat_currency = self.config.get('fiat_display_currency', None) # Calculate amount buy_limit = self.get_target_bid(self.exchange.get_ticker(pair)) From 30b72ad98a21f1131e1b7ddb2311ec93007e3915 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 24 Jul 2018 08:20:32 +0100 Subject: [PATCH 14/19] don't show fiat-currency if not set --- freqtrade/rpc/telegram.py | 8 +++++--- freqtrade/tests/rpc/test_rpc_telegram.py | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index a63422970..f11fa4232 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -125,9 +125,11 @@ class Telegram(RPC): message = "*{exchange}:* Buying [{pair}]({market_url})\n" \ "with limit `{limit:.8f}\n" \ - "({stake_amount:.6f} {stake_currency}," \ - "{stake_amount_fiat:.3f} {fiat_currency})`" \ - .format(**msg) + "({stake_amount:.6f} {stake_currency}".format(**msg) + + if msg.get('fiat_currency', None): + message += ",{stake_amount_fiat:.3f} {fiat_currency}".format(**msg) + message += ")`" elif msg['type'] == RPCMessageType.SELL_NOTIFICATION: msg['amount'] = round(msg['amount'], 8) diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py index da4279a06..1ce8a26f1 100644 --- a/freqtrade/tests/rpc/test_rpc_telegram.py +++ b/freqtrade/tests/rpc/test_rpc_telegram.py @@ -1219,12 +1219,12 @@ def test_send_msg_buy_notification_no_fiat(default_conf, mocker) -> None: 'stake_amount': 0.001, 'stake_amount_fiat': 0.0, 'stake_currency': 'BTC', - 'fiat_currency': 'USD' + 'fiat_currency': None }) assert msg_mock.call_args[0][0] \ == '*Bittrex:* Buying [ETH/BTC](https://bittrex.com/Market/Index?MarketName=BTC-ETH)\n' \ 'with limit `0.00001099\n' \ - '(0.001000 BTC,0.000 USD)`' + '(0.001000 BTC)`' def test_send_msg_sell_notification_no_fiat(default_conf, mocker) -> None: From 4928686af91dcb4f0cc052e9d9cbabfc6dd3b03f Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 24 Jul 2018 09:35:05 +0100 Subject: [PATCH 15/19] Remove currency from daily table --- freqtrade/rpc/rpc.py | 2 +- freqtrade/rpc/telegram.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 1fc99fd98..1e83f5eb9 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -173,7 +173,7 @@ class RPC(object): stake_currency, fiat_display_currency ) if self._fiat_converter else 0, - symbol=fiat_display_currency + symbol=fiat_display_currency if fiat_display_currency else '' ), '{value} trade{s}'.format( value=value['trades'], diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index f11fa4232..de0c50ab6 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -241,7 +241,7 @@ class Telegram(RPC): headers=[ 'Day', f'Profit {stake_cur}', - f'Profit {fiat_disp_cur}' + f'Profit {fiat_disp_cur if fiat_disp_cur else ""}' ], tablefmt='simple') message = f'Daily Profit over the last {timescale} days:\n
{stats}
' From ff6435948e3105439e3e6e4e5dc417d130fda85a Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 24 Jul 2018 22:53:10 +0100 Subject: [PATCH 16/19] Fix random test failure --- freqtrade/tests/rpc/test_rpc_telegram.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py index 1ce8a26f1..63ef3ca91 100644 --- a/freqtrade/tests/rpc/test_rpc_telegram.py +++ b/freqtrade/tests/rpc/test_rpc_telegram.py @@ -1119,6 +1119,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None: ) freqtradebot = get_patched_freqtradebot(mocker, default_conf) telegram = Telegram(freqtradebot) + old_convamount = telegram._fiat_converter.convert_amount telegram._fiat_converter.convert_amount = lambda a, b, c: -24.812 telegram.send_msg({ 'type': RPCMessageType.SELL_NOTIFICATION, @@ -1167,7 +1168,8 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None: '*Open Rate:* `0.00007500`\n' \ '*Current Rate:* `0.00003201`\n' \ '*Profit:* `-57.41%`' - + # Reset singleton function to avoid random breaks + telegram._fiat_converter.convert_amount = old_convamount def test_send_msg_status_notification(default_conf, mocker) -> None: msg_mock = MagicMock() From dc1ad3cbf6eb9846b8db4a3ff57f5081237c431c Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 24 Jul 2018 23:08:40 +0100 Subject: [PATCH 17/19] whitespace issues --- freqtrade/rpc/rpc.py | 3 +-- freqtrade/tests/rpc/test_rpc_telegram.py | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 1e83f5eb9..2b48f956e 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -16,7 +16,6 @@ from pandas import DataFrame from freqtrade.fiat_convert import CryptoToFiatConverter from freqtrade.misc import shorten_date from freqtrade.persistence import Trade - from freqtrade.state import State logger = logging.getLogger(__name__) @@ -50,7 +49,7 @@ class RPC(object): """ RPC class can be used to have extra feature, like bot data, and access to DB data """ - # Initialize _fiat_converter if needed in each RPC handler + # Bind _fiat_converter if needed in each RPC handler _fiat_converter: Optional[CryptoToFiatConverter] = None def __init__(self, freqtrade) -> None: diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py index 63ef3ca91..b2cab6d37 100644 --- a/freqtrade/tests/rpc/test_rpc_telegram.py +++ b/freqtrade/tests/rpc/test_rpc_telegram.py @@ -1171,6 +1171,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None: # Reset singleton function to avoid random breaks telegram._fiat_converter.convert_amount = old_convamount + def test_send_msg_status_notification(default_conf, mocker) -> None: msg_mock = MagicMock() mocker.patch.multiple( From 7b49f746d1d1dc49da4887be0b1e6b9b61e990ca Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 25 Jul 2018 22:47:20 +0100 Subject: [PATCH 18/19] remove #FIX which was fixed --- freqtrade/rpc/rpc.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 2b48f956e..ab80a9ab2 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -226,8 +226,6 @@ class RPC(object): bp_pair, bp_rate = best_pair - # FIX: we want to keep fiatconverter in a state/environment, - # doing this will utilize its caching functionallity, instead we reinitialize it here # Prepare data to display profit_closed_coin_sum = round(sum(profit_closed_coin), 8) profit_closed_percent = round(nan_to_num(mean(profit_closed_percent)) * 100, 2) From 452a1cad9d9306c2b34e40fbd219997ca8286e9c Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 26 Jul 2018 07:26:23 +0100 Subject: [PATCH 19/19] don't default fiat_convert to None for outputs --- freqtrade/rpc/rpc.py | 2 +- freqtrade/rpc/telegram.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index ab80a9ab2..bbb1ea9e5 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -172,7 +172,7 @@ class RPC(object): stake_currency, fiat_display_currency ) if self._fiat_converter else 0, - symbol=fiat_display_currency if fiat_display_currency else '' + symbol=fiat_display_currency ), '{value} trade{s}'.format( value=value['trades'], diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index de0c50ab6..3b5ce3f74 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -226,7 +226,7 @@ class Telegram(RPC): :return: None """ stake_cur = self._config['stake_currency'] - fiat_disp_cur = self._config.get('fiat_display_currency', None) + fiat_disp_cur = self._config.get('fiat_display_currency', '') try: timescale = int(update.message.text.replace('/daily', '').strip()) except (TypeError, ValueError): @@ -241,7 +241,7 @@ class Telegram(RPC): headers=[ 'Day', f'Profit {stake_cur}', - f'Profit {fiat_disp_cur if fiat_disp_cur else ""}' + f'Profit {fiat_disp_cur}' ], tablefmt='simple') message = f'Daily Profit over the last {timescale} days:\n
{stats}
' @@ -259,7 +259,7 @@ class Telegram(RPC): :return: None """ stake_cur = self._config['stake_currency'] - fiat_disp_cur = self._config.get('fiat_display_currency', None) + fiat_disp_cur = self._config.get('fiat_display_currency', '') try: stats = self._rpc_trade_statistics( @@ -298,7 +298,7 @@ class Telegram(RPC): def _balance(self, bot: Bot, update: Update) -> None: """ Handler for /balance """ try: - result = self._rpc_balance(self._config.get('fiat_display_currency', None)) + result = self._rpc_balance(self._config.get('fiat_display_currency', '')) output = '' for currency in result['currencies']: output += "*{currency}:*\n" \