diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index a6ec70636..cd75a7229 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -116,8 +116,8 @@ class Exchange(object): api.urls['api'] = api.urls['test'] logger.info("Enabled Sandbox API on %s", name) else: - logger.warning(self, "No Sandbox URL in CCXT, exiting. " - "Please check your config.json") + logger.warning(self._api.name, "No Sandbox URL in CCXT, exiting. " + "Please check your config.json") raise OperationalException(f'Exchange {name} does not provide a sandbox api') def validate_pairs(self, pairs: List[str]) -> None: diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 706435017..ba081d960 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -94,6 +94,8 @@ class FreqtradeBot(object): 'status': f'{state.name.lower()}' }) logger.info('Changing state to: %s', state.name) + if state == State.RUNNING: + self._startup_messages() if state == State.STOPPED: time.sleep(1) @@ -110,6 +112,38 @@ class FreqtradeBot(object): nb_assets=nb_assets) return state + def _startup_messages(self) -> None: + if self.config.get('dry_run', False): + self.rpc.send_msg({ + 'type': RPCMessageType.WARNING_NOTIFICATION, + 'status': 'Dry run is enabled. All trades are simulated.' + }) + stake_currency = self.config['stake_currency'] + stake_amount = self.config['stake_amount'] + minimal_roi = self.config['minimal_roi'] + ticker_interval = self.config['ticker_interval'] + exchange_name = self.config['exchange']['name'] + strategy_name = self.config.get('strategy', '') + self.rpc.send_msg({ + 'type': RPCMessageType.CUSTOM_NOTIFICATION, + 'status': f'*Exchange:* `{exchange_name}`\n' + f'*Stake per trade:* `{stake_amount} {stake_currency}`\n' + f'*Minimum ROI:* `{minimal_roi}`\n' + f'*Ticker Interval:* `{ticker_interval}`\n' + f'*Strategy:* `{strategy_name}`' + }) + if self.config.get('dynamic_whitelist', False): + top_pairs = 'top ' + str(self.config.get('dynamic_whitelist', False)) + specific_pairs = '' + else: + top_pairs = 'whitelisted' + specific_pairs = '\n' + ', '.join(self.config['exchange'].get('pair_whitelist', '')) + self.rpc.send_msg({ + 'type': RPCMessageType.STATUS_NOTIFICATION, + 'status': f'Searching for {top_pairs} {stake_currency} pairs to buy and sell...\ + {specific_pairs}' + }) + def _throttle(self, func: Callable[..., Any], min_secs: float, *args, **kwargs) -> Any: """ Throttles the given callable that it diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index f58fbae9a..80bac0dd4 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -24,6 +24,8 @@ logger = logging.getLogger(__name__) class RPCMessageType(Enum): STATUS_NOTIFICATION = 'status' + WARNING_NOTIFICATION = 'warning' + CUSTOM_NOTIFICATION = 'custom' BUY_NOTIFICATION = 'buy' SELL_NOTIFICATION = 'sell' diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 3b5ce3f74..64708ef74 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -154,6 +154,12 @@ class Telegram(RPC): elif msg['type'] == RPCMessageType.STATUS_NOTIFICATION: message = '*Status:* `{status}`'.format(**msg) + elif msg['type'] == RPCMessageType.WARNING_NOTIFICATION: + message = '*Warning:* `{status}`'.format(**msg) + + elif msg['type'] == RPCMessageType.CUSTOM_NOTIFICATION: + message = '{status}'.format(**msg) + else: raise NotImplementedError('Unknown message type: {}'.format(msg['type'])) diff --git a/freqtrade/tests/test_talib.py b/freqtrade/tests/test_talib.py index 093c3023c..0fefbccb3 100644 --- a/freqtrade/tests/test_talib.py +++ b/freqtrade/tests/test_talib.py @@ -13,4 +13,4 @@ def test_talib_bollingerbands_near_zero_values(): {'close': 0.00000014} ]) bollinger = ta.BBANDS(inputs, matype=0, timeperiod=2) - assert (bollinger['upperband'][3] != bollinger['middleband'][3]) + assert (bollinger['upperband'][3] == bollinger['middleband'][3])