use native python logger
This commit is contained in:
		| @@ -1,6 +1,7 @@ | |||||||
| """ | """ | ||||||
| Functions to analyze ticker data with indicators and produce buy and sell signals | Functions to analyze ticker data with indicators and produce buy and sell signals | ||||||
| """ | """ | ||||||
|  | import logging | ||||||
| from datetime import datetime, timedelta | from datetime import datetime, timedelta | ||||||
| from enum import Enum | from enum import Enum | ||||||
| from typing import Dict, List, Tuple | from typing import Dict, List, Tuple | ||||||
| @@ -9,12 +10,14 @@ import arrow | |||||||
| from pandas import DataFrame, to_datetime | from pandas import DataFrame, to_datetime | ||||||
|  |  | ||||||
| from freqtrade.exchange import get_ticker_history | from freqtrade.exchange import get_ticker_history | ||||||
| from freqtrade.logger import Logger |  | ||||||
| from freqtrade.persistence import Trade | from freqtrade.persistence import Trade | ||||||
| from freqtrade.strategy.strategy import Strategy | from freqtrade.strategy.strategy import Strategy | ||||||
| from freqtrade.constants import Constants | from freqtrade.constants import Constants | ||||||
|  |  | ||||||
|  |  | ||||||
|  | logger = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  |  | ||||||
| class SignalType(Enum): | class SignalType(Enum): | ||||||
|     """ |     """ | ||||||
|     Enum to distinguish between buy and sell signals |     Enum to distinguish between buy and sell signals | ||||||
| @@ -33,8 +36,6 @@ class Analyze(object): | |||||||
|         Init Analyze |         Init Analyze | ||||||
|         :param config: Bot configuration (use the one from Configuration()) |         :param config: Bot configuration (use the one from Configuration()) | ||||||
|         """ |         """ | ||||||
|         self.logger = Logger(name=__name__, level=config.get('loglevel')).get_logger() |  | ||||||
|  |  | ||||||
|         self.config = config |         self.config = config | ||||||
|         self.strategy = Strategy(self.config) |         self.strategy = Strategy(self.config) | ||||||
|  |  | ||||||
| @@ -110,20 +111,20 @@ class Analyze(object): | |||||||
|         """ |         """ | ||||||
|         ticker_hist = get_ticker_history(pair, interval) |         ticker_hist = get_ticker_history(pair, interval) | ||||||
|         if not ticker_hist: |         if not ticker_hist: | ||||||
|             self.logger.warning('Empty ticker history for pair %s', pair) |             logger.warning('Empty ticker history for pair %s', pair) | ||||||
|             return False, False |             return False, False | ||||||
|  |  | ||||||
|         try: |         try: | ||||||
|             dataframe = self.analyze_ticker(ticker_hist) |             dataframe = self.analyze_ticker(ticker_hist) | ||||||
|         except ValueError as error: |         except ValueError as error: | ||||||
|             self.logger.warning( |             logger.warning( | ||||||
|                 'Unable to analyze ticker for pair %s: %s', |                 'Unable to analyze ticker for pair %s: %s', | ||||||
|                 pair, |                 pair, | ||||||
|                 str(error) |                 str(error) | ||||||
|             ) |             ) | ||||||
|             return False, False |             return False, False | ||||||
|         except Exception as error: |         except Exception as error: | ||||||
|             self.logger.exception( |             logger.exception( | ||||||
|                 'Unexpected error when analyzing ticker for pair %s: %s', |                 'Unexpected error when analyzing ticker for pair %s: %s', | ||||||
|                 pair, |                 pair, | ||||||
|                 str(error) |                 str(error) | ||||||
| @@ -131,7 +132,7 @@ class Analyze(object): | |||||||
|             return False, False |             return False, False | ||||||
|  |  | ||||||
|         if dataframe.empty: |         if dataframe.empty: | ||||||
|             self.logger.warning('Empty dataframe for pair %s', pair) |             logger.warning('Empty dataframe for pair %s', pair) | ||||||
|             return False, False |             return False, False | ||||||
|  |  | ||||||
|         latest = dataframe.iloc[-1] |         latest = dataframe.iloc[-1] | ||||||
| @@ -140,7 +141,7 @@ class Analyze(object): | |||||||
|         signal_date = arrow.get(latest['date']) |         signal_date = arrow.get(latest['date']) | ||||||
|         interval_minutes = Constants.TICKER_INTERVAL_MINUTES[interval] |         interval_minutes = Constants.TICKER_INTERVAL_MINUTES[interval] | ||||||
|         if signal_date < arrow.utcnow() - timedelta(minutes=(interval_minutes + 5)): |         if signal_date < arrow.utcnow() - timedelta(minutes=(interval_minutes + 5)): | ||||||
|             self.logger.warning( |             logger.warning( | ||||||
|                 'Outdated history for pair %s. Last tick is %s minutes old', |                 'Outdated history for pair %s. Last tick is %s minutes old', | ||||||
|                 pair, |                 pair, | ||||||
|                 (arrow.utcnow() - signal_date).seconds // 60 |                 (arrow.utcnow() - signal_date).seconds // 60 | ||||||
| @@ -148,7 +149,7 @@ class Analyze(object): | |||||||
|             return False, False |             return False, False | ||||||
|  |  | ||||||
|         (buy, sell) = latest[SignalType.BUY.value] == 1, latest[SignalType.SELL.value] == 1 |         (buy, sell) = latest[SignalType.BUY.value] == 1, latest[SignalType.SELL.value] == 1 | ||||||
|         self.logger.debug( |         logger.debug( | ||||||
|             'trigger: %s (pair=%s) buy=%s sell=%s', |             'trigger: %s (pair=%s) buy=%s sell=%s', | ||||||
|             latest['date'], |             latest['date'], | ||||||
|             pair, |             pair, | ||||||
| @@ -165,17 +166,17 @@ class Analyze(object): | |||||||
|         """ |         """ | ||||||
|         # Check if minimal roi has been reached and no longer in buy conditions (avoiding a fee) |         # Check if minimal roi has been reached and no longer in buy conditions (avoiding a fee) | ||||||
|         if self.min_roi_reached(trade=trade, current_rate=rate, current_time=date): |         if self.min_roi_reached(trade=trade, current_rate=rate, current_time=date): | ||||||
|             self.logger.debug('Required profit reached. Selling..') |             logger.debug('Required profit reached. Selling..') | ||||||
|             return True |             return True | ||||||
|  |  | ||||||
|         # Experimental: Check if the trade is profitable before selling it (avoid selling at loss) |         # Experimental: Check if the trade is profitable before selling it (avoid selling at loss) | ||||||
|         if self.config.get('experimental', {}).get('sell_profit_only', False): |         if self.config.get('experimental', {}).get('sell_profit_only', False): | ||||||
|             self.logger.debug('Checking if trade is profitable..') |             logger.debug('Checking if trade is profitable..') | ||||||
|             if trade.calc_profit(rate=rate) <= 0: |             if trade.calc_profit(rate=rate) <= 0: | ||||||
|                 return False |                 return False | ||||||
|  |  | ||||||
|         if sell and not buy and self.config.get('experimental', {}).get('use_sell_signal', False): |         if sell and not buy and self.config.get('experimental', {}).get('use_sell_signal', False): | ||||||
|             self.logger.debug('Sell signal received. Selling..') |             logger.debug('Sell signal received. Selling..') | ||||||
|             return True |             return True | ||||||
|  |  | ||||||
|         return False |         return False | ||||||
| @@ -188,7 +189,7 @@ class Analyze(object): | |||||||
|         """ |         """ | ||||||
|         current_profit = trade.calc_profit_percent(current_rate) |         current_profit = trade.calc_profit_percent(current_rate) | ||||||
|         if self.strategy.stoploss is not None and current_profit < self.strategy.stoploss: |         if self.strategy.stoploss is not None and current_profit < self.strategy.stoploss: | ||||||
|             self.logger.debug('Stop loss hit.') |             logger.debug('Stop loss hit.') | ||||||
|             return True |             return True | ||||||
|  |  | ||||||
|         # Check if time matches and current rate is above threshold |         # Check if time matches and current rate is above threshold | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ This module contains the configuration class | |||||||
| """ | """ | ||||||
|  |  | ||||||
| import json | import json | ||||||
|  | import logging | ||||||
| from argparse import Namespace | from argparse import Namespace | ||||||
| from typing import Dict, Any | from typing import Dict, Any | ||||||
| from jsonschema import Draft4Validator, validate | from jsonschema import Draft4Validator, validate | ||||||
| @@ -11,7 +12,9 @@ import ccxt | |||||||
|  |  | ||||||
| from freqtrade import OperationalException | from freqtrade import OperationalException | ||||||
| from freqtrade.constants import Constants | from freqtrade.constants import Constants | ||||||
| from freqtrade.logger import Logger |  | ||||||
|  |  | ||||||
|  | logger = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  |  | ||||||
| class Configuration(object): | class Configuration(object): | ||||||
| @@ -21,8 +24,6 @@ class Configuration(object): | |||||||
|     """ |     """ | ||||||
|     def __init__(self, args: Namespace) -> None: |     def __init__(self, args: Namespace) -> None: | ||||||
|         self.args = args |         self.args = args | ||||||
|         self.logging = Logger(name=__name__) |  | ||||||
|         self.logger = self.logging.get_logger() |  | ||||||
|         self.config = None |         self.config = None | ||||||
|  |  | ||||||
|     def load_config(self) -> Dict[str, Any]: |     def load_config(self) -> Dict[str, Any]: | ||||||
| @@ -30,7 +31,7 @@ class Configuration(object): | |||||||
|         Extract information for sys.argv and load the bot configuration |         Extract information for sys.argv and load the bot configuration | ||||||
|         :return: Configuration dictionary |         :return: Configuration dictionary | ||||||
|         """ |         """ | ||||||
|         self.logger.info('Using config: %s ...', self.args.config) |         logger.info('Using config: %s ...', self.args.config) | ||||||
|         config = self._load_config_file(self.args.config) |         config = self._load_config_file(self.args.config) | ||||||
|  |  | ||||||
|         # Add the strategy file to use |         # Add the strategy file to use | ||||||
| @@ -57,7 +58,7 @@ class Configuration(object): | |||||||
|             with open(path) as file: |             with open(path) as file: | ||||||
|                 conf = json.load(file) |                 conf = json.load(file) | ||||||
|         except FileNotFoundError: |         except FileNotFoundError: | ||||||
|             self.logger.critical( |             logger.critical( | ||||||
|                 'Config file "%s" not found. Please create your config file', |                 'Config file "%s" not found. Please create your config file', | ||||||
|                 path |                 path | ||||||
|             ) |             ) | ||||||
| @@ -65,7 +66,7 @@ class Configuration(object): | |||||||
|  |  | ||||||
|         if 'internals' not in conf: |         if 'internals' not in conf: | ||||||
|             conf['internals'] = {} |             conf['internals'] = {} | ||||||
|         self.logger.info('Validating configuration ...') |         logger.info('Validating configuration ...') | ||||||
|  |  | ||||||
|         return self._validate_config(conf) |         return self._validate_config(conf) | ||||||
|  |  | ||||||
| @@ -78,13 +79,16 @@ class Configuration(object): | |||||||
|         # Log level |         # Log level | ||||||
|         if 'loglevel' in self.args and self.args.loglevel: |         if 'loglevel' in self.args and self.args.loglevel: | ||||||
|             config.update({'loglevel': self.args.loglevel}) |             config.update({'loglevel': self.args.loglevel}) | ||||||
|             self.logging.set_level(self.args.loglevel) |             logging.basicConfig( | ||||||
|             self.logger.info('Log level set at %s', config['loglevel']) |                 level=config['loglevel'], | ||||||
|  |                 format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', | ||||||
|  |             ) | ||||||
|  |             logger.info('Log level set to %s', logging.getLevelName(config['loglevel'])) | ||||||
|  |  | ||||||
|         # Add dynamic_whitelist if found |         # Add dynamic_whitelist if found | ||||||
|         if 'dynamic_whitelist' in self.args and self.args.dynamic_whitelist: |         if 'dynamic_whitelist' in self.args and self.args.dynamic_whitelist: | ||||||
|             config.update({'dynamic_whitelist': self.args.dynamic_whitelist}) |             config.update({'dynamic_whitelist': self.args.dynamic_whitelist}) | ||||||
|             self.logger.info( |             logger.info( | ||||||
|                 'Parameter --dynamic-whitelist detected. ' |                 'Parameter --dynamic-whitelist detected. ' | ||||||
|                 'Using dynamically generated whitelist. ' |                 'Using dynamically generated whitelist. ' | ||||||
|                 '(not applicable with Backtesting and Hyperopt)' |                 '(not applicable with Backtesting and Hyperopt)' | ||||||
| @@ -93,13 +97,13 @@ class Configuration(object): | |||||||
|         # Add dry_run_db if found and the bot in dry run |         # Add dry_run_db if found and the bot in dry run | ||||||
|         if self.args.dry_run_db and config.get('dry_run', False): |         if self.args.dry_run_db and config.get('dry_run', False): | ||||||
|             config.update({'dry_run_db': True}) |             config.update({'dry_run_db': True}) | ||||||
|             self.logger.info('Parameter --dry-run-db detected ...') |             logger.info('Parameter --dry-run-db detected ...') | ||||||
|  |  | ||||||
|         if config.get('dry_run_db', False): |         if config.get('dry_run_db', False): | ||||||
|             if config.get('dry_run', False): |             if config.get('dry_run', False): | ||||||
|                 self.logger.info('Dry_run will use the DB file: "tradesv3.dry_run.sqlite"') |                 logger.info('Dry_run will use the DB file: "tradesv3.dry_run.sqlite"') | ||||||
|             else: |             else: | ||||||
|                 self.logger.info('Dry run is disabled. (--dry_run_db ignored)') |                 logger.info('Dry run is disabled. (--dry_run_db ignored)') | ||||||
|  |  | ||||||
|         # Check if the exchange set by the user is supported |         # Check if the exchange set by the user is supported | ||||||
|         self.check_exchange(config) |         self.check_exchange(config) | ||||||
| @@ -116,39 +120,39 @@ class Configuration(object): | |||||||
|         # (that will override the strategy configuration) |         # (that will override the strategy configuration) | ||||||
|         if 'ticker_interval' in self.args and self.args.ticker_interval: |         if 'ticker_interval' in self.args and self.args.ticker_interval: | ||||||
|             config.update({'ticker_interval': self.args.ticker_interval}) |             config.update({'ticker_interval': self.args.ticker_interval}) | ||||||
|             self.logger.info('Parameter -i/--ticker-interval detected ...') |             logger.info('Parameter -i/--ticker-interval detected ...') | ||||||
|             self.logger.info('Using ticker_interval: %s ...', config.get('ticker_interval')) |             logger.info('Using ticker_interval: %s ...', config.get('ticker_interval')) | ||||||
|  |  | ||||||
|         # If -l/--live is used we add it to the configuration |         # If -l/--live is used we add it to the configuration | ||||||
|         if 'live' in self.args and self.args.live: |         if 'live' in self.args and self.args.live: | ||||||
|             config.update({'live': True}) |             config.update({'live': True}) | ||||||
|             self.logger.info('Parameter -l/--live detected ...') |             logger.info('Parameter -l/--live detected ...') | ||||||
|  |  | ||||||
|         # If --realistic-simulation is used we add it to the configuration |         # If --realistic-simulation is used we add it to the configuration | ||||||
|         if 'realistic_simulation' in self.args and self.args.realistic_simulation: |         if 'realistic_simulation' in self.args and self.args.realistic_simulation: | ||||||
|             config.update({'realistic_simulation': True}) |             config.update({'realistic_simulation': True}) | ||||||
|             self.logger.info('Parameter --realistic-simulation detected ...') |             logger.info('Parameter --realistic-simulation detected ...') | ||||||
|         self.logger.info('Using max_open_trades: %s ...', config.get('max_open_trades')) |         logger.info('Using max_open_trades: %s ...', config.get('max_open_trades')) | ||||||
|  |  | ||||||
|         # If --timerange is used we add it to the configuration |         # If --timerange is used we add it to the configuration | ||||||
|         if 'timerange' in self.args and self.args.timerange: |         if 'timerange' in self.args and self.args.timerange: | ||||||
|             config.update({'timerange': self.args.timerange}) |             config.update({'timerange': self.args.timerange}) | ||||||
|             self.logger.info('Parameter --timerange detected: %s ...', self.args.timerange) |             logger.info('Parameter --timerange detected: %s ...', self.args.timerange) | ||||||
|  |  | ||||||
|         # If --datadir is used we add it to the configuration |         # If --datadir is used we add it to the configuration | ||||||
|         if 'datadir' in self.args and self.args.datadir: |         if 'datadir' in self.args and self.args.datadir: | ||||||
|             config.update({'datadir': self.args.datadir}) |             config.update({'datadir': self.args.datadir}) | ||||||
|             self.logger.info('Parameter --datadir detected: %s ...', self.args.datadir) |             logger.info('Parameter --datadir detected: %s ...', self.args.datadir) | ||||||
|  |  | ||||||
|         # If -r/--refresh-pairs-cached is used we add it to the configuration |         # If -r/--refresh-pairs-cached is used we add it to the configuration | ||||||
|         if 'refresh_pairs' in self.args and self.args.refresh_pairs: |         if 'refresh_pairs' in self.args and self.args.refresh_pairs: | ||||||
|             config.update({'refresh_pairs': True}) |             config.update({'refresh_pairs': True}) | ||||||
|             self.logger.info('Parameter -r/--refresh-pairs-cached detected ...') |             logger.info('Parameter -r/--refresh-pairs-cached detected ...') | ||||||
|  |  | ||||||
|         # If --export is used we add it to the configuration |         # If --export is used we add it to the configuration | ||||||
|         if 'export' in self.args and self.args.export: |         if 'export' in self.args and self.args.export: | ||||||
|             config.update({'export': self.args.export}) |             config.update({'export': self.args.export}) | ||||||
|             self.logger.info('Parameter --export detected: %s ...', self.args.export) |             logger.info('Parameter --export detected: %s ...', self.args.export) | ||||||
|  |  | ||||||
|         return config |         return config | ||||||
|  |  | ||||||
| @@ -160,18 +164,18 @@ class Configuration(object): | |||||||
|         # If --realistic-simulation is used we add it to the configuration |         # If --realistic-simulation is used we add it to the configuration | ||||||
|         if 'epochs' in self.args and self.args.epochs: |         if 'epochs' in self.args and self.args.epochs: | ||||||
|             config.update({'epochs': self.args.epochs}) |             config.update({'epochs': self.args.epochs}) | ||||||
|             self.logger.info('Parameter --epochs detected ...') |             logger.info('Parameter --epochs detected ...') | ||||||
|             self.logger.info('Will run Hyperopt with for %s epochs ...', config.get('epochs')) |             logger.info('Will run Hyperopt with for %s epochs ...', config.get('epochs')) | ||||||
|  |  | ||||||
|         # If --mongodb is used we add it to the configuration |         # If --mongodb is used we add it to the configuration | ||||||
|         if 'mongodb' in self.args and self.args.mongodb: |         if 'mongodb' in self.args and self.args.mongodb: | ||||||
|             config.update({'mongodb': self.args.mongodb}) |             config.update({'mongodb': self.args.mongodb}) | ||||||
|             self.logger.info('Parameter --use-mongodb detected ...') |             logger.info('Parameter --use-mongodb detected ...') | ||||||
|  |  | ||||||
|         # If --spaces is used we add it to the configuration |         # If --spaces is used we add it to the configuration | ||||||
|         if 'spaces' in self.args and self.args.spaces: |         if 'spaces' in self.args and self.args.spaces: | ||||||
|             config.update({'spaces': self.args.spaces}) |             config.update({'spaces': self.args.spaces}) | ||||||
|             self.logger.info('Parameter -s/--spaces detected: %s', config.get('spaces')) |             logger.info('Parameter -s/--spaces detected: %s', config.get('spaces')) | ||||||
|  |  | ||||||
|         return config |         return config | ||||||
|  |  | ||||||
| @@ -185,7 +189,7 @@ class Configuration(object): | |||||||
|             validate(conf, Constants.CONF_SCHEMA) |             validate(conf, Constants.CONF_SCHEMA) | ||||||
|             return conf |             return conf | ||||||
|         except ValidationError as exception: |         except ValidationError as exception: | ||||||
|             self.logger.fatal( |             logger.fatal( | ||||||
|                 'Invalid configuration. See config.json.example. Reason: %s', |                 'Invalid configuration. See config.json.example. Reason: %s', | ||||||
|                 exception |                 exception | ||||||
|             ) |             ) | ||||||
| @@ -215,10 +219,10 @@ class Configuration(object): | |||||||
|                             'The following exchanges are supported: {}'\ |                             'The following exchanges are supported: {}'\ | ||||||
|                 .format(exchange, ', '.join(ccxt.exchanges)) |                 .format(exchange, ', '.join(ccxt.exchanges)) | ||||||
|  |  | ||||||
|             self.logger.critical(exception_msg) |             logger.critical(exception_msg) | ||||||
|             raise OperationalException( |             raise OperationalException( | ||||||
|                 exception_msg |                 exception_msg | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
|         self.logger.debug('Exchange "%s" supported', exchange) |         logger.debug('Exchange "%s" supported', exchange) | ||||||
|         return True |         return True | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ Freqtrade is the main module of this bot. It contains the class Freqtrade() | |||||||
|  |  | ||||||
| import copy | import copy | ||||||
| import json | import json | ||||||
|  | import logging | ||||||
| import time | import time | ||||||
| import traceback | import traceback | ||||||
| from datetime import datetime | from datetime import datetime | ||||||
| @@ -13,16 +14,20 @@ import arrow | |||||||
| import requests | import requests | ||||||
| from cachetools import cached, TTLCache | from cachetools import cached, TTLCache | ||||||
|  |  | ||||||
| from freqtrade import (DependencyException, OperationalException, exchange, persistence) | from freqtrade import ( | ||||||
|  |     DependencyException, OperationalException, exchange, persistence, __version__ | ||||||
|  | ) | ||||||
| from freqtrade.analyze import Analyze | from freqtrade.analyze import Analyze | ||||||
| from freqtrade.constants import Constants | from freqtrade.constants import Constants | ||||||
| from freqtrade.fiat_convert import CryptoToFiatConverter | from freqtrade.fiat_convert import CryptoToFiatConverter | ||||||
| from freqtrade.logger import Logger |  | ||||||
| from freqtrade.persistence import Trade | from freqtrade.persistence import Trade | ||||||
| from freqtrade.rpc.rpc_manager import RPCManager | from freqtrade.rpc.rpc_manager import RPCManager | ||||||
| from freqtrade.state import State | from freqtrade.state import State | ||||||
|  |  | ||||||
|  |  | ||||||
|  | logger = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  |  | ||||||
| class FreqtradeBot(object): | class FreqtradeBot(object): | ||||||
|     """ |     """ | ||||||
|     Freqtrade is the main class of the bot. |     Freqtrade is the main class of the bot. | ||||||
| @@ -37,8 +42,10 @@ class FreqtradeBot(object): | |||||||
|         :param db_url: database connector string for sqlalchemy (Optional) |         :param db_url: database connector string for sqlalchemy (Optional) | ||||||
|         """ |         """ | ||||||
|  |  | ||||||
|         # Init the logger |         logger.info( | ||||||
|         self.logger = Logger(name=__name__, level=config.get('loglevel')).get_logger() |             'Starting freqtrade %s', | ||||||
|  |             __version__, | ||||||
|  |         ) | ||||||
|  |  | ||||||
|         # Init bot states |         # Init bot states | ||||||
|         self.state = State.STOPPED |         self.state = State.STOPPED | ||||||
| @@ -81,7 +88,7 @@ class FreqtradeBot(object): | |||||||
|         :return: None |         :return: None | ||||||
|         """ |         """ | ||||||
|         self.rpc.send_msg('*Status:* `Stopping trader...`') |         self.rpc.send_msg('*Status:* `Stopping trader...`') | ||||||
|         self.logger.info('Stopping trader and cleaning up modules...') |         logger.info('Stopping trader and cleaning up modules...') | ||||||
|         self.state = State.STOPPED |         self.state = State.STOPPED | ||||||
|         self.rpc.cleanup() |         self.rpc.cleanup() | ||||||
|         persistence.cleanup() |         persistence.cleanup() | ||||||
| @@ -97,7 +104,7 @@ class FreqtradeBot(object): | |||||||
|         state = self.state |         state = self.state | ||||||
|         if state != old_state: |         if state != old_state: | ||||||
|             self.rpc.send_msg('*Status:* `{}`'.format(state.name.lower())) |             self.rpc.send_msg('*Status:* `{}`'.format(state.name.lower())) | ||||||
|             self.logger.info('Changing state to: %s', state.name) |             logger.info('Changing state to: %s', state.name) | ||||||
|  |  | ||||||
|         if state == State.STOPPED: |         if state == State.STOPPED: | ||||||
|             time.sleep(1) |             time.sleep(1) | ||||||
| @@ -126,7 +133,7 @@ class FreqtradeBot(object): | |||||||
|         result = func(*args, **kwargs) |         result = func(*args, **kwargs) | ||||||
|         end = time.time() |         end = time.time() | ||||||
|         duration = max(min_secs - (end - start), 0.0) |         duration = max(min_secs - (end - start), 0.0) | ||||||
|         self.logger.debug('Throttling %s for %.2f seconds', func.__name__, duration) |         logger.debug('Throttling %s for %.2f seconds', func.__name__, duration) | ||||||
|         time.sleep(duration) |         time.sleep(duration) | ||||||
|         return result |         return result | ||||||
|  |  | ||||||
| @@ -167,7 +174,7 @@ class FreqtradeBot(object): | |||||||
|                 Trade.session.flush() |                 Trade.session.flush() | ||||||
|  |  | ||||||
|         except (requests.exceptions.RequestException, json.JSONDecodeError) as error: |         except (requests.exceptions.RequestException, json.JSONDecodeError) as error: | ||||||
|             self.logger.warning('%s, retrying in 30 seconds...', error) |             logger.warning('%s, retrying in 30 seconds...', error) | ||||||
|             time.sleep(Constants.RETRY_TIMEOUT) |             time.sleep(Constants.RETRY_TIMEOUT) | ||||||
|         except OperationalException: |         except OperationalException: | ||||||
|             self.rpc.send_msg( |             self.rpc.send_msg( | ||||||
| @@ -177,7 +184,7 @@ class FreqtradeBot(object): | |||||||
|                     hint='Issue `/start` if you think it is safe to restart.' |                     hint='Issue `/start` if you think it is safe to restart.' | ||||||
|                 ) |                 ) | ||||||
|             ) |             ) | ||||||
|             self.logger.exception('OperationalException. Stopping trader ...') |             logger.exception('OperationalException. Stopping trader ...') | ||||||
|             self.state = State.STOPPED |             self.state = State.STOPPED | ||||||
|         return state_changed |         return state_changed | ||||||
|  |  | ||||||
| @@ -228,7 +235,7 @@ class FreqtradeBot(object): | |||||||
|             # Market is not active |             # Market is not active | ||||||
|             if not market['active']: |             if not market['active']: | ||||||
|                 sanitized_whitelist.remove(pair) |                 sanitized_whitelist.remove(pair) | ||||||
|                 self.logger.info( |                 logger.info( | ||||||
|                     'Ignoring %s from whitelist. Market is not active.', |                     'Ignoring %s from whitelist. Market is not active.', | ||||||
|                     pair |                     pair | ||||||
|                 ) |                 ) | ||||||
| @@ -260,7 +267,7 @@ class FreqtradeBot(object): | |||||||
|         stake_amount = self.config['stake_amount'] |         stake_amount = self.config['stake_amount'] | ||||||
|         interval = self.analyze.get_ticker_interval() |         interval = self.analyze.get_ticker_interval() | ||||||
|  |  | ||||||
|         self.logger.info( |         logger.info( | ||||||
|             'Checking buy signals to create a new trade with stake_amount: %f ...', |             'Checking buy signals to create a new trade with stake_amount: %f ...', | ||||||
|             stake_amount |             stake_amount | ||||||
|         ) |         ) | ||||||
| @@ -275,7 +282,7 @@ class FreqtradeBot(object): | |||||||
|         for trade in Trade.query.filter(Trade.is_open.is_(True)).all(): |         for trade in Trade.query.filter(Trade.is_open.is_(True)).all(): | ||||||
|             if trade.pair in whitelist: |             if trade.pair in whitelist: | ||||||
|                 whitelist.remove(trade.pair) |                 whitelist.remove(trade.pair) | ||||||
|                 self.logger.debug('Ignoring %s in pair whitelist', trade.pair) |                 logger.debug('Ignoring %s in pair whitelist', trade.pair) | ||||||
|  |  | ||||||
|         if not whitelist: |         if not whitelist: | ||||||
|             raise DependencyException('No currency pairs in whitelist') |             raise DependencyException('No currency pairs in whitelist') | ||||||
| @@ -340,10 +347,10 @@ class FreqtradeBot(object): | |||||||
|             if self.create_trade(): |             if self.create_trade(): | ||||||
|                 return True |                 return True | ||||||
|  |  | ||||||
|             self.logger.info('Found no buy signals for whitelisted currencies. Trying again..') |             logger.info('Found no buy signals for whitelisted currencies. Trying again..') | ||||||
|             return False |             return False | ||||||
|         except DependencyException as exception: |         except DependencyException as exception: | ||||||
|             self.logger.warning('Unable to create trade: %s', exception) |             logger.warning('Unable to create trade: %s', exception) | ||||||
|             return False |             return False | ||||||
|  |  | ||||||
|     def process_maybe_execute_sell(self, trade: Trade) -> bool: |     def process_maybe_execute_sell(self, trade: Trade) -> bool: | ||||||
| @@ -354,7 +361,7 @@ class FreqtradeBot(object): | |||||||
|         # Get order details for actual price per unit |         # Get order details for actual price per unit | ||||||
|         if trade.open_order_id: |         if trade.open_order_id: | ||||||
|             # Update trade with order values |             # Update trade with order values | ||||||
|             self.logger.info('Found open order for %s', trade) |             logger.info('Found open order for %s', trade) | ||||||
|             trade.update(exchange.get_order(trade.open_order_id, trade.pair)) |             trade.update(exchange.get_order(trade.open_order_id, trade.pair)) | ||||||
|  |  | ||||||
|         if trade.is_open and trade.open_order_id is None: |         if trade.is_open and trade.open_order_id is None: | ||||||
| @@ -370,7 +377,7 @@ class FreqtradeBot(object): | |||||||
|         if not trade.is_open: |         if not trade.is_open: | ||||||
|             raise ValueError('attempt to handle closed trade: {}'.format(trade)) |             raise ValueError('attempt to handle closed trade: {}'.format(trade)) | ||||||
|  |  | ||||||
|         self.logger.debug('Handling %s ...', trade) |         logger.debug('Handling %s ...', trade) | ||||||
|         current_rate = exchange.get_ticker(trade.pair)['bid'] |         current_rate = exchange.get_ticker(trade.pair)['bid'] | ||||||
|  |  | ||||||
|         (buy, sell) = (False, False) |         (buy, sell) = (False, False) | ||||||
| @@ -396,7 +403,7 @@ class FreqtradeBot(object): | |||||||
|             try: |             try: | ||||||
|                 order = exchange.get_order(trade.open_order_id, trade.pair) |                 order = exchange.get_order(trade.open_order_id, trade.pair) | ||||||
|             except requests.exceptions.RequestException: |             except requests.exceptions.RequestException: | ||||||
|                 self.logger.info( |                 logger.info( | ||||||
|                     'Cannot query order for %s due to %s', |                     'Cannot query order for %s due to %s', | ||||||
|                     trade, |                     trade, | ||||||
|                     traceback.format_exc()) |                     traceback.format_exc()) | ||||||
| @@ -426,7 +433,7 @@ class FreqtradeBot(object): | |||||||
|             # FIX? do we really need to flush, caller of |             # FIX? do we really need to flush, caller of | ||||||
|             #      check_handle_timedout will flush afterwards |             #      check_handle_timedout will flush afterwards | ||||||
|             Trade.session.flush() |             Trade.session.flush() | ||||||
|             self.logger.info('Buy order timeout for %s.', trade) |             logger.info('Buy order timeout for %s.', trade) | ||||||
|             self.rpc.send_msg('*Timeout:* Unfilled buy order for {} cancelled'.format( |             self.rpc.send_msg('*Timeout:* Unfilled buy order for {} cancelled'.format( | ||||||
|                 trade.pair.replace('_', '/'))) |                 trade.pair.replace('_', '/'))) | ||||||
|             return True |             return True | ||||||
| @@ -436,7 +443,7 @@ class FreqtradeBot(object): | |||||||
|         trade.amount = order['amount'] - order['remaining'] |         trade.amount = order['amount'] - order['remaining'] | ||||||
|         trade.stake_amount = trade.amount * trade.open_rate |         trade.stake_amount = trade.amount * trade.open_rate | ||||||
|         trade.open_order_id = None |         trade.open_order_id = None | ||||||
|         self.logger.info('Partial buy order timeout for %s.', trade) |         logger.info('Partial buy order timeout for %s.', trade) | ||||||
|         self.rpc.send_msg('*Timeout:* Remaining buy order for {} cancelled'.format( |         self.rpc.send_msg('*Timeout:* Remaining buy order for {} cancelled'.format( | ||||||
|             trade.pair.replace('_', '/'))) |             trade.pair.replace('_', '/'))) | ||||||
|         return False |         return False | ||||||
| @@ -457,7 +464,7 @@ class FreqtradeBot(object): | |||||||
|             trade.open_order_id = None |             trade.open_order_id = None | ||||||
|             self.rpc.send_msg('*Timeout:* Unfilled sell order for {} cancelled'.format( |             self.rpc.send_msg('*Timeout:* Unfilled sell order for {} cancelled'.format( | ||||||
|                 trade.pair.replace('_', '/'))) |                 trade.pair.replace('_', '/'))) | ||||||
|             self.logger.info('Sell order timeout for %s.', trade) |             logger.info('Sell order timeout for %s.', trade) | ||||||
|             return True |             return True | ||||||
|  |  | ||||||
|         # TODO: figure out how to handle partially complete sell orders |         # TODO: figure out how to handle partially complete sell orders | ||||||
|   | |||||||
| @@ -1,83 +0,0 @@ | |||||||
| # pragma pylint: disable=too-few-public-methods |  | ||||||
|  |  | ||||||
| """ |  | ||||||
| This module contains the class for logger and logging messages |  | ||||||
| """ |  | ||||||
|  |  | ||||||
| import logging |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class Logger(object): |  | ||||||
|     """ |  | ||||||
|     Logging class |  | ||||||
|     """ |  | ||||||
|     def __init__(self, name='', level=logging.INFO) -> None: |  | ||||||
|         """ |  | ||||||
|         Init the logger class |  | ||||||
|         :param name: Name of the Logger scope |  | ||||||
|         :param level: Logger level that should be used |  | ||||||
|         :return: None |  | ||||||
|         """ |  | ||||||
|         self.name = name |  | ||||||
|         self.logger = None |  | ||||||
|  |  | ||||||
|         if level is None: |  | ||||||
|             level = logging.INFO |  | ||||||
|         self.level = level |  | ||||||
|  |  | ||||||
|         self._init_logger() |  | ||||||
|  |  | ||||||
|     def _init_logger(self) -> None: |  | ||||||
|         """ |  | ||||||
|         Setup the bot logger configuration |  | ||||||
|         :return: None |  | ||||||
|         """ |  | ||||||
|         logging.basicConfig( |  | ||||||
|             level=self.level, |  | ||||||
|             format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|         self.logger = self.get_logger() |  | ||||||
|         self.set_level(self.level) |  | ||||||
|  |  | ||||||
|     def get_logger(self) -> logging.RootLogger: |  | ||||||
|         """ |  | ||||||
|         Return the logger instance to use for sending message |  | ||||||
|         :return: the logger instance |  | ||||||
|         """ |  | ||||||
|         return logging.getLogger(self.name) |  | ||||||
|  |  | ||||||
|     def set_name(self, name: str) -> logging.RootLogger: |  | ||||||
|         """ |  | ||||||
|         Set the name of the logger |  | ||||||
|         :param name: Name of the logger |  | ||||||
|         :return: None |  | ||||||
|         """ |  | ||||||
|         self.name = name |  | ||||||
|         self.logger = self.get_logger() |  | ||||||
|         return self.logger |  | ||||||
|  |  | ||||||
|     def set_level(self, level) -> None: |  | ||||||
|         """ |  | ||||||
|         Set the level of the logger |  | ||||||
|         :param level: |  | ||||||
|         :return: None |  | ||||||
|         """ |  | ||||||
|         self.level = level |  | ||||||
|         self.logger.setLevel(self.level) |  | ||||||
|  |  | ||||||
|     def set_format(self, log_format: str, propagate: bool = False) -> None: |  | ||||||
|         """ |  | ||||||
|         Set a new logging format |  | ||||||
|         :return: None |  | ||||||
|         """ |  | ||||||
|         handler = logging.StreamHandler() |  | ||||||
|  |  | ||||||
|         len_handlers = len(self.logger.handlers) |  | ||||||
|         if len_handlers: |  | ||||||
|             self.logger.removeHandler(handler) |  | ||||||
|  |  | ||||||
|         handler.setFormatter(logging.Formatter(log_format)) |  | ||||||
|         self.logger.addHandler(handler) |  | ||||||
|  |  | ||||||
|         self.logger.propagate = propagate |  | ||||||
| @@ -8,13 +8,11 @@ import logging | |||||||
| import sys | import sys | ||||||
| from typing import List | from typing import List | ||||||
|  |  | ||||||
| from freqtrade import (__version__) |  | ||||||
| from freqtrade.arguments import Arguments | from freqtrade.arguments import Arguments | ||||||
| from freqtrade.configuration import Configuration | from freqtrade.configuration import Configuration | ||||||
| from freqtrade.freqtradebot import FreqtradeBot | from freqtrade.freqtradebot import FreqtradeBot | ||||||
| from freqtrade.logger import Logger |  | ||||||
|  |  | ||||||
| logger = Logger(name='freqtrade').get_logger() | logger = logging.getLogger('freqtrade') | ||||||
|  |  | ||||||
|  |  | ||||||
| def main(sysargv: List[str]) -> None: | def main(sysargv: List[str]) -> None: | ||||||
| @@ -34,19 +32,13 @@ def main(sysargv: List[str]) -> None: | |||||||
|         args.func(args) |         args.func(args) | ||||||
|         return 0 |         return 0 | ||||||
|  |  | ||||||
|     logger.info( |  | ||||||
|         'Starting freqtrade %s (loglevel=%s)', |  | ||||||
|         __version__, |  | ||||||
|         logging.getLevelName(args.loglevel) |  | ||||||
|     ) |  | ||||||
|  |  | ||||||
|     freqtrade = None |     freqtrade = None | ||||||
|     try: |     try: | ||||||
|         # Load and validate configuration |         # Load and validate configuration | ||||||
|         configuration = Configuration(args) |         config = Configuration(args).get_config() | ||||||
|  |  | ||||||
|         # Init the bot |         # Init the bot | ||||||
|         freqtrade = FreqtradeBot(configuration.get_config()) |         freqtrade = FreqtradeBot(config) | ||||||
|  |  | ||||||
|         state = None |         state = None | ||||||
|         while 1: |         while 1: | ||||||
|   | |||||||
| @@ -2,15 +2,15 @@ | |||||||
|  |  | ||||||
| import gzip | import gzip | ||||||
| import json | import json | ||||||
|  | import logging | ||||||
| import os | import os | ||||||
| from typing import Optional, List, Dict, Tuple | from typing import Optional, List, Dict, Tuple | ||||||
|  |  | ||||||
| from freqtrade import misc | from freqtrade import misc | ||||||
| from freqtrade.exchange import get_ticker_history | from freqtrade.exchange import get_ticker_history | ||||||
| from freqtrade.logger import Logger |  | ||||||
| from user_data.hyperopt_conf import hyperopt_optimize_conf | from user_data.hyperopt_conf import hyperopt_optimize_conf | ||||||
|  |  | ||||||
| logger = Logger(name=__name__).get_logger() | logger = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  |  | ||||||
| def trim_tickerlist(tickerlist: List[Dict], timerange: Tuple[Tuple, int, int]) -> List[Dict]: | def trim_tickerlist(tickerlist: List[Dict], timerange: Tuple[Tuple, int, int]) -> List[Dict]: | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ | |||||||
| """ | """ | ||||||
| This module contains the backtesting logic | This module contains the backtesting logic | ||||||
| """ | """ | ||||||
|  | import logging | ||||||
| from argparse import Namespace | from argparse import Namespace | ||||||
| from typing import Dict, Tuple, Any, List, Optional | from typing import Dict, Tuple, Any, List, Optional | ||||||
|  |  | ||||||
| @@ -15,11 +16,13 @@ from freqtrade import exchange | |||||||
| from freqtrade.analyze import Analyze | from freqtrade.analyze import Analyze | ||||||
| from freqtrade.arguments import Arguments | from freqtrade.arguments import Arguments | ||||||
| from freqtrade.configuration import Configuration | from freqtrade.configuration import Configuration | ||||||
| from freqtrade.logger import Logger |  | ||||||
| from freqtrade.misc import file_dump_json | from freqtrade.misc import file_dump_json | ||||||
| from freqtrade.persistence import Trade | from freqtrade.persistence import Trade | ||||||
|  |  | ||||||
|  |  | ||||||
|  | logger = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  |  | ||||||
| class Backtesting(object): | class Backtesting(object): | ||||||
|     """ |     """ | ||||||
|     Backtesting class, this class contains all the logic to run a backtest |     Backtesting class, this class contains all the logic to run a backtest | ||||||
| @@ -29,10 +32,6 @@ class Backtesting(object): | |||||||
|     backtesting.start() |     backtesting.start() | ||||||
|     """ |     """ | ||||||
|     def __init__(self, config: Dict[str, Any]) -> None: |     def __init__(self, config: Dict[str, Any]) -> None: | ||||||
|  |  | ||||||
|         # Init the logger |  | ||||||
|         self.logging = Logger(name=__name__, level=config['loglevel']) |  | ||||||
|         self.logger = self.logging.get_logger() |  | ||||||
|         self.config = config |         self.config = config | ||||||
|         self.analyze = None |         self.analyze = None | ||||||
|         self.ticker_interval = None |         self.ticker_interval = None | ||||||
| @@ -206,7 +205,7 @@ class Backtesting(object): | |||||||
|         # For now export inside backtest(), maybe change so that backtest() |         # For now export inside backtest(), maybe change so that backtest() | ||||||
|         # returns a tuple like: (dataframe, records, logs, etc) |         # returns a tuple like: (dataframe, records, logs, etc) | ||||||
|         if record and record.find('trades') >= 0: |         if record and record.find('trades') >= 0: | ||||||
|             self.logger.info('Dumping backtest results') |             logger.info('Dumping backtest results') | ||||||
|             file_dump_json('backtest-result.json', records) |             file_dump_json('backtest-result.json', records) | ||||||
|         labels = ['currency', 'profit_percent', 'profit_BTC', 'duration'] |         labels = ['currency', 'profit_percent', 'profit_BTC', 'duration'] | ||||||
|         return DataFrame.from_records(trades, columns=labels) |         return DataFrame.from_records(trades, columns=labels) | ||||||
| @@ -218,15 +217,15 @@ class Backtesting(object): | |||||||
|         """ |         """ | ||||||
|         data = {} |         data = {} | ||||||
|         pairs = self.config['exchange']['pair_whitelist'] |         pairs = self.config['exchange']['pair_whitelist'] | ||||||
|         self.logger.info('Using stake_currency: %s ...', self.config['stake_currency']) |         logger.info('Using stake_currency: %s ...', self.config['stake_currency']) | ||||||
|         self.logger.info('Using stake_amount: %s ...', self.config['stake_amount']) |         logger.info('Using stake_amount: %s ...', self.config['stake_amount']) | ||||||
|  |  | ||||||
|         if self.config.get('live'): |         if self.config.get('live'): | ||||||
|             self.logger.info('Downloading data for all pairs in whitelist ...') |             logger.info('Downloading data for all pairs in whitelist ...') | ||||||
|             for pair in pairs: |             for pair in pairs: | ||||||
|                 data[pair] = exchange.get_ticker_history(pair, self.ticker_interval) |                 data[pair] = exchange.get_ticker_history(pair, self.ticker_interval) | ||||||
|         else: |         else: | ||||||
|             self.logger.info('Using local backtesting data (using whitelist in given config) ...') |             logger.info('Using local backtesting data (using whitelist in given config) ...') | ||||||
|  |  | ||||||
|             timerange = Arguments.parse_timerange(self.config.get('timerange')) |             timerange = Arguments.parse_timerange(self.config.get('timerange')) | ||||||
|             data = optimize.load_data( |             data = optimize.load_data( | ||||||
| @@ -241,14 +240,14 @@ class Backtesting(object): | |||||||
|         if self.config.get('realistic_simulation', False): |         if self.config.get('realistic_simulation', False): | ||||||
|             max_open_trades = self.config['max_open_trades'] |             max_open_trades = self.config['max_open_trades'] | ||||||
|         else: |         else: | ||||||
|             self.logger.info('Ignoring max_open_trades (realistic_simulation not set) ...') |             logger.info('Ignoring max_open_trades (realistic_simulation not set) ...') | ||||||
|             max_open_trades = 0 |             max_open_trades = 0 | ||||||
|  |  | ||||||
|         preprocessed = self.tickerdata_to_dataframe(data) |         preprocessed = self.tickerdata_to_dataframe(data) | ||||||
|  |  | ||||||
|         # Print timeframe |         # Print timeframe | ||||||
|         min_date, max_date = self.get_timeframe(preprocessed) |         min_date, max_date = self.get_timeframe(preprocessed) | ||||||
|         self.logger.info( |         logger.info( | ||||||
|             'Measuring data from %s up to %s (%s days)..', |             'Measuring data from %s up to %s (%s days)..', | ||||||
|             min_date.isoformat(), |             min_date.isoformat(), | ||||||
|             max_date.isoformat(), |             max_date.isoformat(), | ||||||
| @@ -269,9 +268,7 @@ class Backtesting(object): | |||||||
|                 'record': self.config.get('export') |                 'record': self.config.get('export') | ||||||
|             } |             } | ||||||
|         ) |         ) | ||||||
|  |         logger.info( | ||||||
|         self.logging.set_format('%(message)s') |  | ||||||
|         self.logger.info( |  | ||||||
|             '\n==================================== ' |             '\n==================================== ' | ||||||
|             'BACKTESTING REPORT' |             'BACKTESTING REPORT' | ||||||
|             ' ====================================\n' |             ' ====================================\n' | ||||||
| @@ -307,7 +304,6 @@ def start(args: Namespace) -> None: | |||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     # Initialize logger |     # Initialize logger | ||||||
|     logger = Logger(name=__name__).get_logger() |  | ||||||
|     logger.info('Starting freqtrade in Backtesting mode') |     logger.info('Starting freqtrade in Backtesting mode') | ||||||
|  |  | ||||||
|     # Initialize configuration |     # Initialize configuration | ||||||
|   | |||||||
| @@ -25,12 +25,14 @@ from pandas import DataFrame | |||||||
| import freqtrade.vendor.qtpylib.indicators as qtpylib | import freqtrade.vendor.qtpylib.indicators as qtpylib | ||||||
| from freqtrade.arguments import Arguments | from freqtrade.arguments import Arguments | ||||||
| from freqtrade.configuration import Configuration | from freqtrade.configuration import Configuration | ||||||
| from freqtrade.logger import Logger |  | ||||||
| from freqtrade.optimize import load_data | from freqtrade.optimize import load_data | ||||||
| from freqtrade.optimize.backtesting import Backtesting | from freqtrade.optimize.backtesting import Backtesting | ||||||
| from user_data.hyperopt_conf import hyperopt_optimize_conf | from user_data.hyperopt_conf import hyperopt_optimize_conf | ||||||
|  |  | ||||||
|  |  | ||||||
|  | logger = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  |  | ||||||
| class Hyperopt(Backtesting): | class Hyperopt(Backtesting): | ||||||
|     """ |     """ | ||||||
|     Hyperopt class, this class contains all the logic to run a hyperopt simulation |     Hyperopt class, this class contains all the logic to run a hyperopt simulation | ||||||
| @@ -42,11 +44,6 @@ class Hyperopt(Backtesting): | |||||||
|     def __init__(self, config: Dict[str, Any]) -> None: |     def __init__(self, config: Dict[str, Any]) -> None: | ||||||
|  |  | ||||||
|         super().__init__(config) |         super().__init__(config) | ||||||
|  |  | ||||||
|         # Rename the logging to display Hyperopt file instead of Backtesting |  | ||||||
|         self.logging = Logger(name=__name__, level=config['loglevel']) |  | ||||||
|         self.logger = self.logging.get_logger() |  | ||||||
|  |  | ||||||
|         # set TARGET_TRADES to suit your number concurrent trades so its realistic |         # set TARGET_TRADES to suit your number concurrent trades so its realistic | ||||||
|         # to the number of days |         # to the number of days | ||||||
|         self.target_trades = 600 |         self.target_trades = 600 | ||||||
| @@ -194,14 +191,14 @@ class Hyperopt(Backtesting): | |||||||
|         """ |         """ | ||||||
|         Save hyperopt trials to file |         Save hyperopt trials to file | ||||||
|         """ |         """ | ||||||
|         self.logger.info('Saving Trials to \'%s\'', self.trials_file) |         logger.info('Saving Trials to \'%s\'', self.trials_file) | ||||||
|         pickle.dump(self.trials, open(self.trials_file, 'wb')) |         pickle.dump(self.trials, open(self.trials_file, 'wb')) | ||||||
|  |  | ||||||
|     def read_trials(self) -> Trials: |     def read_trials(self) -> Trials: | ||||||
|         """ |         """ | ||||||
|         Read hyperopt trials file |         Read hyperopt trials file | ||||||
|         """ |         """ | ||||||
|         self.logger.info('Reading Trials from \'%s\'', self.trials_file) |         logger.info('Reading Trials from \'%s\'', self.trials_file) | ||||||
|         trials = pickle.load(open(self.trials_file, 'rb')) |         trials = pickle.load(open(self.trials_file, 'rb')) | ||||||
|         os.remove(self.trials_file) |         os.remove(self.trials_file) | ||||||
|         return trials |         return trials | ||||||
| @@ -212,7 +209,7 @@ class Hyperopt(Backtesting): | |||||||
|         """ |         """ | ||||||
|         vals = json.dumps(self.trials.best_trial['misc']['vals'], indent=4) |         vals = json.dumps(self.trials.best_trial['misc']['vals'], indent=4) | ||||||
|         results = self.trials.best_trial['result']['result'] |         results = self.trials.best_trial['result']['result'] | ||||||
|         self.logger.info('Best result:\n%s\nwith values:\n%s', results, vals) |         logger.info('Best result:\n%s\nwith values:\n%s', results, vals) | ||||||
|  |  | ||||||
|     def log_results(self, results) -> None: |     def log_results(self, results) -> None: | ||||||
|         """ |         """ | ||||||
| @@ -226,7 +223,7 @@ class Hyperopt(Backtesting): | |||||||
|                 results['result'], |                 results['result'], | ||||||
|                 results['loss'] |                 results['loss'] | ||||||
|             ) |             ) | ||||||
|             self.logger.info(log_msg) |             logger.info(log_msg) | ||||||
|         else: |         else: | ||||||
|             print('.', end='') |             print('.', end='') | ||||||
|             sys.stdout.flush() |             sys.stdout.flush() | ||||||
| @@ -511,8 +508,8 @@ class Hyperopt(Backtesting): | |||||||
|         self.processed = self.tickerdata_to_dataframe(data) |         self.processed = self.tickerdata_to_dataframe(data) | ||||||
|  |  | ||||||
|         if self.config.get('mongodb'): |         if self.config.get('mongodb'): | ||||||
|             self.logger.info('Using mongodb ...') |             logger.info('Using mongodb ...') | ||||||
|             self.logger.info( |             logger.info( | ||||||
|                 'Start scripts/start-mongodb.sh and start-hyperopt-worker.sh manually!' |                 'Start scripts/start-mongodb.sh and start-hyperopt-worker.sh manually!' | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
| @@ -522,7 +519,7 @@ class Hyperopt(Backtesting): | |||||||
|                 exp_key='exp1' |                 exp_key='exp1' | ||||||
|             ) |             ) | ||||||
|         else: |         else: | ||||||
|             self.logger.info('Preparing Trials..') |             logger.info('Preparing Trials..') | ||||||
|             signal.signal(signal.SIGINT, self.signal_handler) |             signal.signal(signal.SIGINT, self.signal_handler) | ||||||
|             # read trials file if we have one |             # read trials file if we have one | ||||||
|             if os.path.exists(self.trials_file) and os.path.getsize(self.trials_file) > 0: |             if os.path.exists(self.trials_file) and os.path.getsize(self.trials_file) > 0: | ||||||
| @@ -530,16 +527,13 @@ class Hyperopt(Backtesting): | |||||||
|  |  | ||||||
|                 self.current_tries = len(self.trials.results) |                 self.current_tries = len(self.trials.results) | ||||||
|                 self.total_tries += self.current_tries |                 self.total_tries += self.current_tries | ||||||
|                 self.logger.info( |                 logger.info( | ||||||
|                     'Continuing with trials. Current: %d, Total: %d', |                     'Continuing with trials. Current: %d, Total: %d', | ||||||
|                     self.current_tries, |                     self.current_tries, | ||||||
|                     self.total_tries |                     self.total_tries | ||||||
|                 ) |                 ) | ||||||
|  |  | ||||||
|         try: |         try: | ||||||
|             # change the Logging format |  | ||||||
|             self.logging.set_format('\n%(message)s') |  | ||||||
|  |  | ||||||
|             best_parameters = fmin( |             best_parameters = fmin( | ||||||
|                 fn=self.generate_optimizer, |                 fn=self.generate_optimizer, | ||||||
|                 space=self.hyperopt_space(), |                 space=self.hyperopt_space(), | ||||||
| @@ -563,11 +557,11 @@ class Hyperopt(Backtesting): | |||||||
|                 best_parameters |                 best_parameters | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
|         self.logger.info('Best parameters:\n%s', json.dumps(best_parameters, indent=4)) |         logger.info('Best parameters:\n%s', json.dumps(best_parameters, indent=4)) | ||||||
|         if 'roi_t1' in best_parameters: |         if 'roi_t1' in best_parameters: | ||||||
|             self.logger.info('ROI table:\n%s', self.generate_roi_table(best_parameters)) |             logger.info('ROI table:\n%s', self.generate_roi_table(best_parameters)) | ||||||
|  |  | ||||||
|         self.logger.info('Best Result:\n%s', best_result) |         logger.info('Best Result:\n%s', best_result) | ||||||
|  |  | ||||||
|         # Store trials result to file to resume next time |         # Store trials result to file to resume next time | ||||||
|         self.save_trials() |         self.save_trials() | ||||||
| @@ -576,7 +570,7 @@ class Hyperopt(Backtesting): | |||||||
|         """ |         """ | ||||||
|         Hyperopt SIGINT handler |         Hyperopt SIGINT handler | ||||||
|         """ |         """ | ||||||
|         self.logger.info( |         logger.info( | ||||||
|             'Hyperopt received %s', |             'Hyperopt received %s', | ||||||
|             signal.Signals(sig).name |             signal.Signals(sig).name | ||||||
|         ) |         ) | ||||||
| @@ -597,8 +591,6 @@ def start(args: Namespace) -> None: | |||||||
|     logging.getLogger('hyperopt.mongoexp').setLevel(logging.WARNING) |     logging.getLogger('hyperopt.mongoexp').setLevel(logging.WARNING) | ||||||
|     logging.getLogger('hyperopt.tpe').setLevel(logging.WARNING) |     logging.getLogger('hyperopt.tpe').setLevel(logging.WARNING) | ||||||
|  |  | ||||||
|     # Initialize logger |  | ||||||
|     logger = Logger(name=__name__).get_logger() |  | ||||||
|     logger.info('Starting freqtrade in Hyperopt mode') |     logger.info('Starting freqtrade in Hyperopt mode') | ||||||
|  |  | ||||||
|     # Initialize configuration |     # Initialize configuration | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| """ | """ | ||||||
| This module contains class to define a RPC communications | This module contains class to define a RPC communications | ||||||
| """ | """ | ||||||
|  | import logging | ||||||
| from datetime import datetime, timedelta | from datetime import datetime, timedelta | ||||||
| from decimal import Decimal | from decimal import Decimal | ||||||
| from typing import Tuple, Any | from typing import Tuple, Any | ||||||
| @@ -11,12 +11,14 @@ import sqlalchemy as sql | |||||||
| from pandas import DataFrame | from pandas import DataFrame | ||||||
|  |  | ||||||
| from freqtrade import exchange | from freqtrade import exchange | ||||||
| from freqtrade.logger import Logger |  | ||||||
| from freqtrade.misc import shorten_date | from freqtrade.misc import shorten_date | ||||||
| from freqtrade.persistence import Trade | from freqtrade.persistence import Trade | ||||||
| from freqtrade.state import State | from freqtrade.state import State | ||||||
|  |  | ||||||
|  |  | ||||||
|  | logger = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  |  | ||||||
| class RPC(object): | class RPC(object): | ||||||
|     """ |     """ | ||||||
|     RPC class can be used to have extra feature, like bot data, and access to DB data |     RPC class can be used to have extra feature, like bot data, and access to DB data | ||||||
| @@ -28,10 +30,6 @@ class RPC(object): | |||||||
|         :return: None |         :return: None | ||||||
|         """ |         """ | ||||||
|         self.freqtrade = freqtrade |         self.freqtrade = freqtrade | ||||||
|         self.logger = Logger( |  | ||||||
|             name=__name__, |  | ||||||
|             level=self.freqtrade.config.get('loglevel') |  | ||||||
|         ).get_logger() |  | ||||||
|  |  | ||||||
|     def rpc_trade_status(self) -> Tuple[bool, Any]: |     def rpc_trade_status(self) -> Tuple[bool, Any]: | ||||||
|         """ |         """ | ||||||
| @@ -350,7 +348,7 @@ class RPC(object): | |||||||
|             ) |             ) | ||||||
|         ).first() |         ).first() | ||||||
|         if not trade: |         if not trade: | ||||||
|             self.logger.warning('forcesell: Invalid argument received') |             logger.warning('forcesell: Invalid argument received') | ||||||
|             return True, 'Invalid argument.' |             return True, 'Invalid argument.' | ||||||
|  |  | ||||||
|         _exec_forcesell(trade) |         _exec_forcesell(trade) | ||||||
|   | |||||||
| @@ -1,11 +1,14 @@ | |||||||
| """ | """ | ||||||
| This module contains class to manage RPC communications (Telegram, Slack, ...) | This module contains class to manage RPC communications (Telegram, Slack, ...) | ||||||
| """ | """ | ||||||
|  | import logging | ||||||
|  |  | ||||||
| from freqtrade.logger import Logger |  | ||||||
| from freqtrade.rpc.telegram import Telegram | from freqtrade.rpc.telegram import Telegram | ||||||
|  |  | ||||||
|  |  | ||||||
|  | logger = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  |  | ||||||
| class RPCManager(object): | class RPCManager(object): | ||||||
|     """ |     """ | ||||||
|     Class to manage RPC objects (Telegram, Slack, ...) |     Class to manage RPC objects (Telegram, Slack, ...) | ||||||
| @@ -18,12 +21,6 @@ class RPCManager(object): | |||||||
|         """ |         """ | ||||||
|         self.freqtrade = freqtrade |         self.freqtrade = freqtrade | ||||||
|  |  | ||||||
|         # Init the logger |  | ||||||
|         self.logger = Logger( |  | ||||||
|             name=__name__, |  | ||||||
|             level=self.freqtrade.config.get('loglevel') |  | ||||||
|         ).get_logger() |  | ||||||
|  |  | ||||||
|         self.registered_modules = [] |         self.registered_modules = [] | ||||||
|         self.telegram = None |         self.telegram = None | ||||||
|         self._init() |         self._init() | ||||||
| @@ -34,7 +31,7 @@ class RPCManager(object): | |||||||
|         :return: |         :return: | ||||||
|         """ |         """ | ||||||
|         if self.freqtrade.config['telegram'].get('enabled', False): |         if self.freqtrade.config['telegram'].get('enabled', False): | ||||||
|             self.logger.info('Enabling rpc.telegram ...') |             logger.info('Enabling rpc.telegram ...') | ||||||
|             self.registered_modules.append('telegram') |             self.registered_modules.append('telegram') | ||||||
|             self.telegram = Telegram(self.freqtrade) |             self.telegram = Telegram(self.freqtrade) | ||||||
|  |  | ||||||
| @@ -44,7 +41,7 @@ class RPCManager(object): | |||||||
|         :return: None |         :return: None | ||||||
|         """ |         """ | ||||||
|         if 'telegram' in self.registered_modules: |         if 'telegram' in self.registered_modules: | ||||||
|             self.logger.info('Cleaning up rpc.telegram ...') |             logger.info('Cleaning up rpc.telegram ...') | ||||||
|             self.registered_modules.remove('telegram') |             self.registered_modules.remove('telegram') | ||||||
|             self.telegram.cleanup() |             self.telegram.cleanup() | ||||||
|  |  | ||||||
| @@ -54,6 +51,6 @@ class RPCManager(object): | |||||||
|         :param msg: message |         :param msg: message | ||||||
|         :return: None |         :return: None | ||||||
|         """ |         """ | ||||||
|         self.logger.info(msg) |         logger.info(msg) | ||||||
|         if 'telegram' in self.registered_modules: |         if 'telegram' in self.registered_modules: | ||||||
|             self.telegram.send_msg(msg) |             self.telegram.send_msg(msg) | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ | |||||||
| """ | """ | ||||||
| This module manage Telegram communication | This module manage Telegram communication | ||||||
| """ | """ | ||||||
|  | import logging | ||||||
| from typing import Any, Callable | from typing import Any, Callable | ||||||
|  |  | ||||||
| from tabulate import tabulate | from tabulate import tabulate | ||||||
| @@ -15,6 +15,9 @@ from freqtrade.__init__ import __version__ | |||||||
| from freqtrade.rpc.rpc import RPC | from freqtrade.rpc.rpc import RPC | ||||||
|  |  | ||||||
|  |  | ||||||
|  | logger = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  |  | ||||||
| def authorized_only(command_handler: Callable[[Bot, Update], None]) -> Callable[..., Any]: | def authorized_only(command_handler: Callable[[Bot, Update], None]) -> Callable[..., Any]: | ||||||
|     """ |     """ | ||||||
|     Decorator to check if the message comes from the correct chat_id |     Decorator to check if the message comes from the correct chat_id | ||||||
| @@ -31,13 +34,13 @@ def authorized_only(command_handler: Callable[[Bot, Update], None]) -> Callable[ | |||||||
|         chat_id = int(self._config['telegram']['chat_id']) |         chat_id = int(self._config['telegram']['chat_id']) | ||||||
|  |  | ||||||
|         if int(update.message.chat_id) != chat_id: |         if int(update.message.chat_id) != chat_id: | ||||||
|             self.logger.info( |             logger.info( | ||||||
|                 'Rejected unauthorized message from: %s', |                 'Rejected unauthorized message from: %s', | ||||||
|                 update.message.chat_id |                 update.message.chat_id | ||||||
|             ) |             ) | ||||||
|             return wrapper |             return wrapper | ||||||
|  |  | ||||||
|         self.logger.info( |         logger.info( | ||||||
|             'Executing handler: %s for chat_id: %s', |             'Executing handler: %s for chat_id: %s', | ||||||
|             command_handler.__name__, |             command_handler.__name__, | ||||||
|             chat_id |             chat_id | ||||||
| @@ -45,7 +48,7 @@ def authorized_only(command_handler: Callable[[Bot, Update], None]) -> Callable[ | |||||||
|         try: |         try: | ||||||
|             return command_handler(self, *args, **kwargs) |             return command_handler(self, *args, **kwargs) | ||||||
|         except BaseException: |         except BaseException: | ||||||
|             self.logger.exception('Exception occurred within Telegram module') |             logger.exception('Exception occurred within Telegram module') | ||||||
|  |  | ||||||
|     return wrapper |     return wrapper | ||||||
|  |  | ||||||
| @@ -101,7 +104,7 @@ class Telegram(RPC): | |||||||
|             timeout=30, |             timeout=30, | ||||||
|             read_latency=60, |             read_latency=60, | ||||||
|         ) |         ) | ||||||
|         self.logger.info( |         logger.info( | ||||||
|             'rpc.telegram is listening for following commands: %s', |             'rpc.telegram is listening for following commands: %s', | ||||||
|             [h.command for h in handles] |             [h.command for h in handles] | ||||||
|         ) |         ) | ||||||
| @@ -357,7 +360,7 @@ class Telegram(RPC): | |||||||
|             'max': [self._config['max_open_trades']] |             'max': [self._config['max_open_trades']] | ||||||
|         }, headers=['current', 'max'], tablefmt='simple') |         }, headers=['current', 'max'], tablefmt='simple') | ||||||
|         message = "<pre>{}</pre>".format(message) |         message = "<pre>{}</pre>".format(message) | ||||||
|         self.logger.debug(message) |         logger.debug(message) | ||||||
|         self.send_msg(message, parse_mode=ParseMode.HTML) |         self.send_msg(message, parse_mode=ParseMode.HTML) | ||||||
|  |  | ||||||
|     @authorized_only |     @authorized_only | ||||||
| @@ -428,7 +431,7 @@ class Telegram(RPC): | |||||||
|             except NetworkError as network_err: |             except NetworkError as network_err: | ||||||
|                 # Sometimes the telegram server resets the current connection, |                 # Sometimes the telegram server resets the current connection, | ||||||
|                 # if this is the case we send the message again. |                 # if this is the case we send the message again. | ||||||
|                 self.logger.warning( |                 logger.warning( | ||||||
|                     'Telegram NetworkError: %s! Trying one more time.', |                     'Telegram NetworkError: %s! Trying one more time.', | ||||||
|                     network_err.message |                     network_err.message | ||||||
|                 ) |                 ) | ||||||
| @@ -439,7 +442,7 @@ class Telegram(RPC): | |||||||
|                     reply_markup=reply_markup |                     reply_markup=reply_markup | ||||||
|                 ) |                 ) | ||||||
|         except TelegramError as telegram_err: |         except TelegramError as telegram_err: | ||||||
|             self.logger.warning( |             logger.warning( | ||||||
|                 'TelegramError: %s! Giving up on that message.', |                 'TelegramError: %s! Giving up on that message.', | ||||||
|                 telegram_err.message |                 telegram_err.message | ||||||
|             ) |             ) | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ | |||||||
| This module load custom strategies | This module load custom strategies | ||||||
| """ | """ | ||||||
| import importlib | import importlib | ||||||
|  | import logging | ||||||
| import os | import os | ||||||
| import sys | import sys | ||||||
| from collections import OrderedDict | from collections import OrderedDict | ||||||
| @@ -11,12 +12,14 @@ from collections import OrderedDict | |||||||
| from pandas import DataFrame | from pandas import DataFrame | ||||||
|  |  | ||||||
| from freqtrade.constants import Constants | from freqtrade.constants import Constants | ||||||
| from freqtrade.logger import Logger |  | ||||||
| from freqtrade.strategy.interface import IStrategy | from freqtrade.strategy.interface import IStrategy | ||||||
|  |  | ||||||
| sys.path.insert(0, r'../../user_data/strategies') | sys.path.insert(0, r'../../user_data/strategies') | ||||||
|  |  | ||||||
|  |  | ||||||
|  | logger = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  |  | ||||||
| class Strategy(object): | class Strategy(object): | ||||||
|     """ |     """ | ||||||
|     This class contains all the logic to load custom strategy class |     This class contains all the logic to load custom strategy class | ||||||
| @@ -27,8 +30,6 @@ class Strategy(object): | |||||||
|         :param config: |         :param config: | ||||||
|         :return: |         :return: | ||||||
|         """ |         """ | ||||||
|         self.logger = Logger(name=__name__).get_logger() |  | ||||||
|  |  | ||||||
|         # Verify the strategy is in the configuration, otherwise fallback to the default strategy |         # Verify the strategy is in the configuration, otherwise fallback to the default strategy | ||||||
|         if 'strategy' in config: |         if 'strategy' in config: | ||||||
|             strategy = config['strategy'] |             strategy = config['strategy'] | ||||||
| @@ -42,17 +43,17 @@ class Strategy(object): | |||||||
|         # Check if we need to override configuration |         # Check if we need to override configuration | ||||||
|         if 'minimal_roi' in config: |         if 'minimal_roi' in config: | ||||||
|             self.custom_strategy.minimal_roi = config['minimal_roi'] |             self.custom_strategy.minimal_roi = config['minimal_roi'] | ||||||
|             self.logger.info("Override strategy \'minimal_roi\' with value in config file.") |             logger.info("Override strategy \'minimal_roi\' with value in config file.") | ||||||
|  |  | ||||||
|         if 'stoploss' in config: |         if 'stoploss' in config: | ||||||
|             self.custom_strategy.stoploss = config['stoploss'] |             self.custom_strategy.stoploss = config['stoploss'] | ||||||
|             self.logger.info( |             logger.info( | ||||||
|                 "Override strategy \'stoploss\' with value in config file: %s.", config['stoploss'] |                 "Override strategy \'stoploss\' with value in config file: %s.", config['stoploss'] | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
|         if 'ticker_interval' in config: |         if 'ticker_interval' in config: | ||||||
|             self.custom_strategy.ticker_interval = config['ticker_interval'] |             self.custom_strategy.ticker_interval = config['ticker_interval'] | ||||||
|             self.logger.info( |             logger.info( | ||||||
|                 "Override strategy \'ticker_interval\' with value in config file: %s.", |                 "Override strategy \'ticker_interval\' with value in config file: %s.", | ||||||
|                 config['ticker_interval'] |                 config['ticker_interval'] | ||||||
|             ) |             ) | ||||||
| @@ -87,12 +88,12 @@ class Strategy(object): | |||||||
|  |  | ||||||
|         # Fallback to the default strategy |         # Fallback to the default strategy | ||||||
|         except (ImportError, TypeError) as error: |         except (ImportError, TypeError) as error: | ||||||
|             self.logger.error( |             logger.error( | ||||||
|                 "Impossible to load Strategy 'user_data/strategies/%s.py'. This file does not exist" |                 "Impossible to load Strategy 'user_data/strategies/%s.py'. This file does not exist" | ||||||
|                 " or contains Python code errors", |                 " or contains Python code errors", | ||||||
|                 strategy_name |                 strategy_name | ||||||
|             ) |             ) | ||||||
|             self.logger.error( |             logger.error( | ||||||
|                 "The error is:\n%s.", |                 "The error is:\n%s.", | ||||||
|                 error |                 error | ||||||
|             ) |             ) | ||||||
| @@ -106,7 +107,7 @@ class Strategy(object): | |||||||
|         module = importlib.import_module(filename, __package__) |         module = importlib.import_module(filename, __package__) | ||||||
|         custom_strategy = getattr(module, module.class_name) |         custom_strategy = getattr(module, module.class_name) | ||||||
|  |  | ||||||
|         self.logger.info("Load strategy class: %s (%s.py)", module.class_name, filename) |         logger.info("Load strategy class: %s (%s.py)", module.class_name, filename) | ||||||
|         return custom_strategy() |         return custom_strategy() | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|   | |||||||
| @@ -64,7 +64,6 @@ def test_start(mocker, default_conf, caplog) -> None: | |||||||
|     Test start() function |     Test start() function | ||||||
|     """ |     """ | ||||||
|     start_mock = MagicMock() |     start_mock = MagicMock() | ||||||
|     mocker.patch('freqtrade.logger.Logger.set_format', MagicMock()) |  | ||||||
|     mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.start', start_mock) |     mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.start', start_mock) | ||||||
|     mocker.patch('freqtrade.optimize.hyperopt.hyperopt_optimize_conf', |     mocker.patch('freqtrade.optimize.hyperopt.hyperopt_optimize_conf', | ||||||
|                  MagicMock(return_value=default_conf)) |                  MagicMock(return_value=default_conf)) | ||||||
| @@ -184,7 +183,6 @@ def test_fmin_best_results(mocker, init_hyperopt, default_conf, caplog) -> None: | |||||||
|     mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock()) |     mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock()) | ||||||
|     mocker.patch('freqtrade.optimize.hyperopt.fmin', return_value=fmin_result) |     mocker.patch('freqtrade.optimize.hyperopt.fmin', return_value=fmin_result) | ||||||
|     mocker.patch('freqtrade.optimize.hyperopt.hyperopt_optimize_conf', return_value=conf) |     mocker.patch('freqtrade.optimize.hyperopt.hyperopt_optimize_conf', return_value=conf) | ||||||
|     mocker.patch('freqtrade.logger.Logger.set_format', MagicMock()) |  | ||||||
|     mocker.patch('freqtrade.freqtradebot.exchange.validate_pairs', MagicMock()) |     mocker.patch('freqtrade.freqtradebot.exchange.validate_pairs', MagicMock()) | ||||||
|  |  | ||||||
|     Strategy({'strategy': 'default_strategy'}) |     Strategy({'strategy': 'default_strategy'}) | ||||||
| @@ -230,7 +228,6 @@ def test_fmin_throw_value_error(mocker, init_hyperopt, default_conf, caplog) -> | |||||||
|     conf.update({'timerange': None}) |     conf.update({'timerange': None}) | ||||||
|     conf.update({'spaces': 'all'}) |     conf.update({'spaces': 'all'}) | ||||||
|     mocker.patch('freqtrade.optimize.hyperopt.hyperopt_optimize_conf', return_value=conf) |     mocker.patch('freqtrade.optimize.hyperopt.hyperopt_optimize_conf', return_value=conf) | ||||||
|     mocker.patch('freqtrade.logger.Logger.set_format', MagicMock()) |  | ||||||
|     mocker.patch('freqtrade.freqtradebot.exchange.validate_pairs', MagicMock()) |     mocker.patch('freqtrade.freqtradebot.exchange.validate_pairs', MagicMock()) | ||||||
|  |  | ||||||
|     Strategy({'strategy': 'default_strategy'}) |     Strategy({'strategy': 'default_strategy'}) | ||||||
| @@ -274,7 +271,6 @@ def test_resuming_previous_hyperopt_results_succeeds(mocker, init_hyperopt, defa | |||||||
|     mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock()) |     mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock()) | ||||||
|     mocker.patch('freqtrade.optimize.hyperopt.fmin', return_value={}) |     mocker.patch('freqtrade.optimize.hyperopt.fmin', return_value={}) | ||||||
|     mocker.patch('freqtrade.optimize.hyperopt.hyperopt_optimize_conf', return_value=conf) |     mocker.patch('freqtrade.optimize.hyperopt.hyperopt_optimize_conf', return_value=conf) | ||||||
|     mocker.patch('freqtrade.logger.Logger.set_format', MagicMock()) |  | ||||||
|     mocker.patch('freqtrade.exchange.validate_pairs', MagicMock()) |     mocker.patch('freqtrade.exchange.validate_pairs', MagicMock()) | ||||||
|  |  | ||||||
|     Strategy({'strategy': 'default_strategy'}) |     Strategy({'strategy': 'default_strategy'}) | ||||||
|   | |||||||
| @@ -29,7 +29,6 @@ def test_strategy_structure(): | |||||||
|  |  | ||||||
| def test_load_strategy(result): | def test_load_strategy(result): | ||||||
|     strategy = Strategy() |     strategy = Strategy() | ||||||
|     strategy.logger = logging.getLogger(__name__) |  | ||||||
|  |  | ||||||
|     assert not hasattr(Strategy, 'custom_strategy') |     assert not hasattr(Strategy, 'custom_strategy') | ||||||
|     strategy._load_strategy('test_strategy') |     strategy._load_strategy('test_strategy') | ||||||
| @@ -42,14 +41,13 @@ def test_load_strategy(result): | |||||||
|  |  | ||||||
| def test_load_not_found_strategy(caplog): | def test_load_not_found_strategy(caplog): | ||||||
|     strategy = Strategy() |     strategy = Strategy() | ||||||
|     strategy.logger = logging.getLogger(__name__) |  | ||||||
|  |  | ||||||
|     assert not hasattr(Strategy, 'custom_strategy') |     assert not hasattr(Strategy, 'custom_strategy') | ||||||
|     strategy._load_strategy('NotFoundStrategy') |     strategy._load_strategy('NotFoundStrategy') | ||||||
|  |  | ||||||
|     error_msg = "Impossible to load Strategy 'user_data/strategies/{}.py'. This file does not " \ |     error_msg = "Impossible to load Strategy 'user_data/strategies/{}.py'. This file does not " \ | ||||||
|                 "exist or contains Python code errors".format('NotFoundStrategy') |                 "exist or contains Python code errors".format('NotFoundStrategy') | ||||||
|     assert ('test_strategy', logging.ERROR, error_msg) in caplog.record_tuples |     assert ('freqtrade.strategy.strategy', logging.ERROR, error_msg) in caplog.record_tuples | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_strategy(result): | def test_strategy(result): | ||||||
|   | |||||||
| @@ -1,97 +0,0 @@ | |||||||
| """ |  | ||||||
| Unit test file for logger.py |  | ||||||
| """ |  | ||||||
|  |  | ||||||
| import logging |  | ||||||
|  |  | ||||||
| from freqtrade.logger import Logger |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_logger_object() -> None: |  | ||||||
|     """ |  | ||||||
|     Test the Constants object has the mandatory Constants |  | ||||||
|     :return: None |  | ||||||
|     """ |  | ||||||
|     logger = Logger() |  | ||||||
|     assert logger.name == '' |  | ||||||
|     assert logger.level == 20 |  | ||||||
|     assert logger.level is logging.INFO |  | ||||||
|     assert hasattr(logger, 'get_logger') |  | ||||||
|  |  | ||||||
|     logger = Logger(name='Foo', level=logging.WARNING) |  | ||||||
|     assert logger.name == 'Foo' |  | ||||||
|     assert logger.name != '' |  | ||||||
|     assert logger.level == 30 |  | ||||||
|     assert logger.level is logging.WARNING |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_get_logger() -> None: |  | ||||||
|     """ |  | ||||||
|     Test Logger.get_logger() and Logger._init_logger() |  | ||||||
|     :return: None |  | ||||||
|     """ |  | ||||||
|     logger = Logger(name='get_logger', level=logging.WARNING) |  | ||||||
|     get_logger = logger.get_logger() |  | ||||||
|     assert logger.logger is get_logger |  | ||||||
|     assert get_logger is not None |  | ||||||
|     assert hasattr(get_logger, 'debug') |  | ||||||
|     assert hasattr(get_logger, 'info') |  | ||||||
|     assert hasattr(get_logger, 'warning') |  | ||||||
|     assert hasattr(get_logger, 'critical') |  | ||||||
|     assert hasattr(get_logger, 'exception') |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_set_name() -> None: |  | ||||||
|     """ |  | ||||||
|     Test Logger.set_name() |  | ||||||
|     :return: None |  | ||||||
|     """ |  | ||||||
|     logger = Logger(name='set_name') |  | ||||||
|     assert logger.name == 'set_name' |  | ||||||
|  |  | ||||||
|     logger.set_name('set_name_new') |  | ||||||
|     assert logger.name == 'set_name_new' |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_set_level() -> None: |  | ||||||
|     """ |  | ||||||
|     Test Logger.set_name() |  | ||||||
|     :return: None |  | ||||||
|     """ |  | ||||||
|     logger = Logger(name='Foo', level=logging.WARNING) |  | ||||||
|     assert logger.level == logging.WARNING |  | ||||||
|     assert logger.get_logger().level == logging.WARNING |  | ||||||
|  |  | ||||||
|     logger.set_level(logging.INFO) |  | ||||||
|     assert logger.level == logging.INFO |  | ||||||
|     assert logger.get_logger().level == logging.INFO |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_sending_msg(caplog) -> None: |  | ||||||
|     """ |  | ||||||
|     Test send a logging message |  | ||||||
|     :return: None |  | ||||||
|     """ |  | ||||||
|     logger = Logger(name='sending_msg', level=logging.WARNING).get_logger() |  | ||||||
|  |  | ||||||
|     logger.info('I am an INFO message') |  | ||||||
|     assert('sending_msg', logging.INFO, 'I am an INFO message') not in caplog.record_tuples |  | ||||||
|  |  | ||||||
|     logger.warning('I am an WARNING message') |  | ||||||
|     assert ('sending_msg', logging.WARNING, 'I am an WARNING message') in caplog.record_tuples |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_set_format(caplog) -> None: |  | ||||||
|     """ |  | ||||||
|     Test Logger.set_format() |  | ||||||
|     :return: None |  | ||||||
|     """ |  | ||||||
|     log = Logger(name='set_format') |  | ||||||
|     logger = log.get_logger() |  | ||||||
|  |  | ||||||
|     logger.info('I am the first message') |  | ||||||
|     assert ('set_format', logging.INFO, 'I am the first message') in caplog.record_tuples |  | ||||||
|  |  | ||||||
|     log.set_format(log_format='%(message)s', propagate=True) |  | ||||||
|     logger.info('I am the second message') |  | ||||||
|     assert ('set_format', logging.INFO, 'I am the second message') in caplog.record_tuples |  | ||||||
| @@ -10,7 +10,7 @@ Optional Cli parameters | |||||||
| --timerange: specify what timerange of data to use. | --timerange: specify what timerange of data to use. | ||||||
| -l / --live: Live, to download the latest ticker for the pair | -l / --live: Live, to download the latest ticker for the pair | ||||||
| """ | """ | ||||||
|  | import logging | ||||||
| import sys | import sys | ||||||
| from argparse import Namespace | from argparse import Namespace | ||||||
| from os import path | from os import path | ||||||
| @@ -22,13 +22,12 @@ import gzip | |||||||
|  |  | ||||||
| from freqtrade.arguments import Arguments | from freqtrade.arguments import Arguments | ||||||
| from freqtrade import misc | from freqtrade import misc | ||||||
| from freqtrade.logger import Logger |  | ||||||
| from pandas import DataFrame | from pandas import DataFrame | ||||||
| from freqtrade.constants import Constants | from freqtrade.constants import Constants | ||||||
|  |  | ||||||
| import dateutil.parser | import dateutil.parser | ||||||
|  |  | ||||||
| logger = Logger(name="freqtrade").get_logger() | logger = logging.getLogger('freqtrade') | ||||||
|  |  | ||||||
|  |  | ||||||
| def load_old_file(filename) -> (List[Dict], bool): | def load_old_file(filename) -> (List[Dict], bool): | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ Optional Cli parameters | |||||||
| --timerange: specify what timerange of data to use. | --timerange: specify what timerange of data to use. | ||||||
| -l / --live: Live, to download the latest ticker for the pair | -l / --live: Live, to download the latest ticker for the pair | ||||||
| """ | """ | ||||||
|  | import logging | ||||||
| import sys | import sys | ||||||
| from argparse import Namespace | from argparse import Namespace | ||||||
|  |  | ||||||
| @@ -24,11 +24,10 @@ import plotly.graph_objs as go | |||||||
| from freqtrade.arguments import Arguments | from freqtrade.arguments import Arguments | ||||||
| from freqtrade.analyze import Analyze | from freqtrade.analyze import Analyze | ||||||
| from freqtrade import exchange | from freqtrade import exchange | ||||||
| from freqtrade.logger import Logger |  | ||||||
| import freqtrade.optimize as optimize | import freqtrade.optimize as optimize | ||||||
|  |  | ||||||
|  |  | ||||||
| logger = Logger(name="Graph dataframe").get_logger() | logger = logging.getLogger('freqtrade') | ||||||
|  |  | ||||||
|  |  | ||||||
| def plot_analyzed_dataframe(args: Namespace) -> None: | def plot_analyzed_dataframe(args: Namespace) -> None: | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ Optional Cli parameters | |||||||
| -s / --strategy: strategy to use | -s / --strategy: strategy to use | ||||||
| --timerange: specify what timerange of data to use. | --timerange: specify what timerange of data to use. | ||||||
| """ | """ | ||||||
|  | import logging | ||||||
| import sys | import sys | ||||||
| import json | import json | ||||||
| from argparse import Namespace | from argparse import Namespace | ||||||
| @@ -24,14 +24,13 @@ import plotly.graph_objs as go | |||||||
| from freqtrade.arguments import Arguments | from freqtrade.arguments import Arguments | ||||||
| from freqtrade.configuration import Configuration | from freqtrade.configuration import Configuration | ||||||
| from freqtrade.analyze import Analyze | from freqtrade.analyze import Analyze | ||||||
| from freqtrade.logger import Logger |  | ||||||
| from freqtrade.constants import Constants | from freqtrade.constants import Constants | ||||||
|  |  | ||||||
| import freqtrade.optimize as optimize | import freqtrade.optimize as optimize | ||||||
| import freqtrade.misc as misc | import freqtrade.misc as misc | ||||||
|  |  | ||||||
|  |  | ||||||
| logger = Logger(name="Graph profits").get_logger() | logger = logging.getLogger('freqtrade') | ||||||
|  |  | ||||||
|  |  | ||||||
| # data:: [ pair,      profit-%,  enter,         exit,        time, duration] | # data:: [ pair,      profit-%,  enter,         exit,        time, duration] | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user