def __init__(self, config: Dict[str, Any]) -> None: self.config = config # Reset keys for backtesting remove_credentials(self.config) self.strategylist: List[IStrategy] = [] self.exchange = ExchangeResolver.load_exchange( self.config['exchange']['name'], self.config) dataprovider = DataProvider(self.config, self.exchange) IStrategy.dp = dataprovider if self.config.get('strategy_list', None): for strat in list(self.config['strategy_list']): stratconf = deepcopy(self.config) stratconf['strategy'] = strat self.strategylist.append( StrategyResolver.load_strategy(stratconf)) validate_config_consistency(stratconf) else: # No strategy list specified, only one strategy self.strategylist.append( StrategyResolver.load_strategy(self.config)) validate_config_consistency(self.config) if "timeframe" not in self.config: raise OperationalException( "Timeframe (ticker interval) needs to be set in either " "configuration or as cli argument `--timeframe 5m`") self.timeframe = str(self.config.get('timeframe')) self.timeframe_min = timeframe_to_minutes(self.timeframe) self.pairlists = PairListManager(self.exchange, self.config) if 'VolumePairList' in self.pairlists.name_list: raise OperationalException( "VolumePairList not allowed for backtesting.") if len(self.strategylist ) > 1 and 'PrecisionFilter' in self.pairlists.name_list: raise OperationalException( "PrecisionFilter not allowed for backtesting multiple strategies." ) self.pairlists.refresh_pairlist() if len(self.pairlists.whitelist) == 0: raise OperationalException("No pair in whitelist.") if config.get('fee', None) is not None: self.fee = config['fee'] else: self.fee = self.exchange.get_fee( symbol=self.pairlists.whitelist[0]) # Get maximum required startup period self.required_startup = max( [strat.startup_candle_count for strat in self.strategylist]) # Load one (first) strategy self._set_strategy(self.strategylist[0])
def test_validate_max_open_trades(default_conf): default_conf['max_open_trades'] = float('inf') default_conf['stake_amount'] = 'unlimited' with pytest.raises(OperationalException, match='`max_open_trades` and `stake_amount` ' 'cannot both be unlimited.'): validate_config_consistency(default_conf)
def test_validate_whitelist(default_conf): default_conf['runmode'] = RunMode.DRY_RUN # Test regular case - has whitelist and uses StaticPairlist validate_config_consistency(default_conf) conf = deepcopy(default_conf) del conf['exchange']['pair_whitelist'] # Test error case with pytest.raises( OperationalException, match="StaticPairList requires pair_whitelist to be set."): validate_config_consistency(conf) conf = deepcopy(default_conf) conf.update({"pairlists": [{ "method": "VolumePairList", }]}) # Dynamic whitelist should not care about pair_whitelist validate_config_consistency(conf) del conf['exchange']['pair_whitelist'] validate_config_consistency(conf) conf = deepcopy(default_conf) conf['stake_currency'] = 'USDT' with pytest.raises( OperationalException, match=r"Stake-currency 'USDT' not compatible with pair-whitelist.*" ): validate_config_consistency(conf)
def test_validate_protections(default_conf, protconf, expected): conf = deepcopy(default_conf) conf['protections'] = protconf if expected: with pytest.raises(OperationalException, match=expected): validate_config_consistency(conf) else: validate_config_consistency(conf)
def __init__(self, config: Dict[str, Any]) -> None: """ Init all variables and objects the bot needs to work :param config: configuration dict, you can use Configuration.get_config() to get the config dict. """ logger.info('Starting freqtrade %s', __version__) # Init bot state self.state = State.STOPPED # Init objects self.config = config self._heartbeat_msg = 0 self.heartbeat_interval = self.config.get('internals', {}).get( 'heartbeat_interval', 60) self.strategy: IStrategy = StrategyResolver(self.config).strategy # Check config consistency here since strategies can set certain options validate_config_consistency(config) self.exchange = ExchangeResolver(self.config['exchange']['name'], self.config).exchange self.wallets = Wallets(self.config, self.exchange) self.dataprovider = DataProvider(self.config, self.exchange) # Attach Dataprovider to Strategy baseclass IStrategy.dp = self.dataprovider # Attach Wallets to Strategy baseclass IStrategy.wallets = self.wallets self.pairlists = PairListManager(self.exchange, self.config) # Initializing Edge only if enabled self.edge = Edge(self.config, self.exchange, self.strategy) if \ self.config.get('edge', {}).get('enabled', False) else None self.active_pair_whitelist = self._refresh_whitelist() persistence.init(self.config.get('db_url', None), clean_open_orders=self.config.get('dry_run', False)) # Set initial bot state from config initial_state = self.config.get('initial_state') self.state = State[ initial_state.upper()] if initial_state else State.STOPPED # RPC runs in separate threads, can start handling external commands just after # initialization, even before Freqtradebot has a chance to start its throttling, # so anything in the Freqtradebot instance should be ready (initialized), including # the initial state of the bot. # Keep this at the end of this initialization method. self.rpc: RPCManager = RPCManager(self)
def __init__(self, config: Dict[str, Any]) -> None: """ Init all variables and objects the bot needs to work :param config: configuration dict, you can use Configuration.get_config() to get the config dict. """ logger.info('Starting freqtrade %s', __version__) # Init bot state self.state = State.STOPPED # Init objects self.config = config self.strategy: IStrategy = StrategyResolver(self.config).strategy # Check config consistency here since strategies can set certain options validate_config_consistency(config) self.rpc: RPCManager = RPCManager(self) self.exchange = ExchangeResolver(self.config['exchange']['name'], self.config).exchange self.wallets = Wallets(self.config, self.exchange) self.dataprovider = DataProvider(self.config, self.exchange) # Attach Dataprovider to Strategy baseclass IStrategy.dp = self.dataprovider # Attach Wallets to Strategy baseclass IStrategy.wallets = self.wallets pairlistname = self.config.get('pairlist', {}).get('method', 'StaticPairList') self.pairlists = PairListResolver(pairlistname, self, self.config).pairlist # Initializing Edge only if enabled self.edge = Edge(self.config, self.exchange, self.strategy) if \ self.config.get('edge', {}).get('enabled', False) else None self.active_pair_whitelist: List[str] = self.config['exchange']['pair_whitelist'] persistence.init(self.config.get('db_url', None), clean_open_orders=self.config.get('dry_run', False)) # Stoploss on exchange does not make sense, therefore we need to disable that. if (self.dataprovider.runmode == RunMode.DRY_RUN and self.strategy.order_types.get('stoploss_on_exchange', False)): logger.info("Disabling stoploss_on_exchange during dry-run.") self.strategy.order_types['stoploss_on_exchange'] = False config['order_types']['stoploss_on_exchange'] = False # Set initial bot state from config initial_state = self.config.get('initial_state') self.state = State[initial_state.upper()] if initial_state else State.STOPPED
def test_validate_edge2(edge_conf): edge_conf.update({"ask_strategy": { "use_sell_signal": True, }}) # Passes test validate_config_consistency(edge_conf) edge_conf.update({"ask_strategy": { "use_sell_signal": False, }}) with pytest.raises(OperationalException, match="Edge requires `use_sell_signal` to be True, " "otherwise no sells will happen."): validate_config_consistency(edge_conf)
def test_validate_edge(edge_conf): edge_conf.update({"pairlist": { "method": "VolumePairList", }}) with pytest.raises(OperationalException, match="Edge and VolumePairList are incompatible, " "Edge will override whatever pairs VolumePairlist selects."): validate_config_consistency(edge_conf) edge_conf.update({"pairlist": { "method": "StaticPairList", }}) validate_config_consistency(edge_conf)
def test_validate_price_side(default_conf): default_conf['order_types'] = { "buy": "limit", "sell": "limit", "stoploss": "limit", "stoploss_on_exchange": False, } # Default should pass validate_config_consistency(default_conf) conf = deepcopy(default_conf) conf['order_types']['buy'] = 'market' with pytest.raises( OperationalException, match='Market buy orders require bid_strategy.price_side = "ask".' ): validate_config_consistency(conf) conf = deepcopy(default_conf) conf['order_types']['sell'] = 'market' with pytest.raises( OperationalException, match='Market sell orders require ask_strategy.price_side = "bid".' ): validate_config_consistency(conf) # Validate inversed case conf = deepcopy(default_conf) conf['order_types']['sell'] = 'market' conf['order_types']['buy'] = 'market' conf['ask_strategy']['price_side'] = 'bid' conf['bid_strategy']['price_side'] = 'ask' validate_config_consistency(conf)
def test_validate_ask_orderbook(default_conf, caplog) -> None: conf = deepcopy(default_conf) conf['ask_strategy']['use_order_book'] = True conf['ask_strategy']['order_book_min'] = 2 conf['ask_strategy']['order_book_max'] = 2 validate_config_consistency(conf) assert log_has_re(r"DEPRECATED: Please use `order_book_top` instead of.*", caplog) assert conf['ask_strategy']['order_book_top'] == 2 conf['ask_strategy']['order_book_max'] = 5 with pytest.raises(OperationalException, match=r"Using order_book_max != order_book_min in ask_strategy.*"): validate_config_consistency(conf)
def __init__(self, config: Dict[str, Any]) -> None: self.config = config # Reset keys for edge remove_credentials(self.config) self.config['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT self.exchange = ExchangeResolver.load_exchange(self.config['exchange']['name'], self.config) self.strategy = StrategyResolver.load_strategy(self.config) validate_config_consistency(self.config) self.edge = Edge(config, self.exchange, self.strategy) # Set refresh_pairs to false for edge-cli (it must be true for edge) self.edge._refresh_pairs = False self.edge._timerange = TimeRange.parse_timerange(None if self.config.get( 'timerange') is None else str(self.config.get('timerange')))
def __init__(self, config: Dict[str, Any]) -> None: self.config = config # Reset keys for backtesting remove_credentials(self.config) self.strategylist: List[IStrategy] = [] self.exchange = ExchangeResolver.load_exchange( self.config['exchange']['name'], self.config) if config.get('fee'): self.fee = config['fee'] else: self.fee = self.exchange.get_fee( symbol=self.config['exchange']['pair_whitelist'][0]) if self.config.get('runmode') != RunMode.HYPEROPT: self.dataprovider = DataProvider(self.config, self.exchange) IStrategy.dp = self.dataprovider if self.config.get('strategy_list', None): for strat in list(self.config['strategy_list']): stratconf = deepcopy(self.config) stratconf['strategy'] = strat self.strategylist.append( StrategyResolver.load_strategy(stratconf)) validate_config_consistency(stratconf) else: # No strategy list specified, only one strategy self.strategylist.append( StrategyResolver.load_strategy(self.config)) validate_config_consistency(self.config) if "ticker_interval" not in self.config: raise OperationalException( "Ticker-interval needs to be set in either configuration " "or as cli argument `--ticker-interval 5m`") self.timeframe = str(self.config.get('ticker_interval')) self.timeframe_min = timeframe_to_minutes(self.timeframe) # Get maximum required startup period self.required_startup = max( [strat.startup_candle_count for strat in self.strategylist]) # Load one (first) strategy self._set_strategy(self.strategylist[0])
def __init__(self, config: Dict[str, Any]) -> None: self.config = config # Ensure using dry-run self.config['dry_run'] = True self.config['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT self.exchange = ExchangeResolver.load_exchange( self.config['exchange']['name'], self.config) self.strategy = StrategyResolver.load_strategy(self.config) self.strategy.dp = DataProvider(config, self.exchange) validate_config_consistency(self.config) self.edge = Edge(config, self.exchange, self.strategy) # Set refresh_pairs to false for edge-cli (it must be true for edge) self.edge._refresh_pairs = False self.edge._timerange = TimeRange.parse_timerange( None if self.config.get('timerange') is None else str( self.config.get('timerange')))
def test_validate_tsl(default_conf): default_conf['stoploss'] = 0.0 with pytest.raises(OperationalException, match='The config stoploss needs to be different ' 'from 0 to avoid problems with sell orders.'): validate_config_consistency(default_conf) default_conf['stoploss'] = -0.10 default_conf['trailing_stop'] = True default_conf['trailing_stop_positive'] = 0 default_conf['trailing_stop_positive_offset'] = 0 default_conf['trailing_only_offset_is_reached'] = True with pytest.raises( OperationalException, match=r'The config trailing_only_offset_is_reached needs ' 'trailing_stop_positive_offset to be more than 0 in your config.'): validate_config_consistency(default_conf) default_conf['trailing_stop_positive_offset'] = 0.01 default_conf['trailing_stop_positive'] = 0.015 with pytest.raises( OperationalException, match=r'The config trailing_stop_positive_offset needs ' 'to be greater than trailing_stop_positive in your config.'): validate_config_consistency(default_conf) default_conf['trailing_stop_positive'] = 0.01 default_conf['trailing_stop_positive_offset'] = 0.015 validate_config_consistency(default_conf) # 0 trailing stop positive - results in "Order would trigger immediately" default_conf['trailing_stop_positive'] = 0 default_conf['trailing_stop_positive_offset'] = 0.02 default_conf['trailing_only_offset_is_reached'] = False with pytest.raises( OperationalException, match= 'The config trailing_stop_positive needs to be different from 0 ' 'to avoid problems with sell orders'): validate_config_consistency(default_conf)
def __init__(self, config: Dict[str, Any]) -> None: LoggingMixin.show_output = False self.config = config self.results: Dict[str, Any] = {} config['dry_run'] = True self.run_ids: Dict[str, str] = {} self.strategylist: List[IStrategy] = [] self.all_results: Dict[str, Dict] = {} self.exchange = ExchangeResolver.load_exchange( self.config['exchange']['name'], self.config) self.dataprovider = DataProvider(self.config, self.exchange) if self.config.get('strategy_list', None): for strat in list(self.config['strategy_list']): stratconf = deepcopy(self.config) stratconf['strategy'] = strat self.strategylist.append( StrategyResolver.load_strategy(stratconf)) validate_config_consistency(stratconf) else: # No strategy list specified, only one strategy self.strategylist.append( StrategyResolver.load_strategy(self.config)) validate_config_consistency(self.config) if "timeframe" not in self.config: raise OperationalException( "Timeframe (ticker interval) needs to be set in either " "configuration or as cli argument `--timeframe 5m`") self.timeframe = str(self.config.get('timeframe')) self.timeframe_min = timeframe_to_minutes(self.timeframe) self.init_backtest_detail() self.pairlists = PairListManager(self.exchange, self.config) if 'VolumePairList' in self.pairlists.name_list: raise OperationalException( "VolumePairList not allowed for backtesting. " "Please use StaticPairlist instead.") if 'PerformanceFilter' in self.pairlists.name_list: raise OperationalException( "PerformanceFilter not allowed for backtesting.") if len(self.strategylist ) > 1 and 'PrecisionFilter' in self.pairlists.name_list: raise OperationalException( "PrecisionFilter not allowed for backtesting multiple strategies." ) self.dataprovider.add_pairlisthandler(self.pairlists) self.pairlists.refresh_pairlist() if len(self.pairlists.whitelist) == 0: raise OperationalException("No pair in whitelist.") if config.get('fee', None) is not None: self.fee = config['fee'] else: self.fee = self.exchange.get_fee( symbol=self.pairlists.whitelist[0]) self.timerange = TimeRange.parse_timerange(None if self.config.get( 'timerange') is None else str(self.config.get('timerange'))) # Get maximum required startup period self.required_startup = max( [strat.startup_candle_count for strat in self.strategylist]) # Add maximum startup candle count to configuration for informative pairs support self.config['startup_candle_count'] = self.required_startup self.exchange.validate_required_startup_candles( self.required_startup, self.timeframe) self.init_backtest()