Ejemplo n.º 1
0
    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])
Ejemplo n.º 2
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)
Ejemplo n.º 3
0
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)
Ejemplo n.º 4
0
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)
Ejemplo n.º 5
0
    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)
Ejemplo n.º 6
0
    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
Ejemplo n.º 7
0
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)
Ejemplo n.º 8
0
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)
Ejemplo n.º 9
0
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)
Ejemplo n.º 10
0
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)
Ejemplo n.º 11
0
    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')))
Ejemplo n.º 12
0
    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])
Ejemplo n.º 13
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)
Ejemplo n.º 15
0
    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()