freqtrade/freqtrade · error · OperationalException

No exchange object found.

Error message

No exchange object found.

What it means

download_all_data_for_training() must enumerate tradable markets via the exchange object attached to DataProvider. dp._exchange is None when the DataProvider was created without a live exchange connection (e.g. pure backtest context), and the helper raises OperationalException because pair discovery is impossible.

Source

Thrown at freqtrade/freqai/utils.py:34

from freqtrade.freqai.data_drawer import FreqaiDataDrawer
from freqtrade.freqai.data_kitchen import FreqaiDataKitchen
from freqtrade.plugins.pairlist.pairlist_helpers import dynamic_expand_pairlist


logger = logging.getLogger(__name__)


def download_all_data_for_training(dp: DataProvider, config: Config) -> None:
    """
    Called only once upon start of bot to download the necessary data for
    populating indicators and training the model.
    :param timerange: TimeRange = The full data timerange for populating the indicators
                                    and training the model.
    :param dp: DataProvider instance attached to the strategy
    """

    if dp._exchange is None:
        raise OperationalException("No exchange object found.")
    markets = [
        p
        for p in dp._exchange.get_markets(
            tradable_only=True, active_only=not config.get("include_inactive")
        ).keys()
    ]

    all_pairs = dynamic_expand_pairlist(config, markets)

    timerange = get_required_data_timerange(config)

    new_pairs_days = int((timerange.stopts - timerange.startts) / 86400)

    refresh_backtest_ohlcv_data(
        dp._exchange,
        pairs=all_pairs,
        timeframes=config["freqai"]["feature_parameters"].get("include_timeframes"),
        datadir=config["datadir"],

View on GitHub (pinned to 1c8edfe4d1)

Solutions

  1. Ensure the config contains a valid 'exchange' section (name, pair_whitelist, etc.) — copy from config_examples and pass it with -c
  2. Run the official entry point: freqtrade download-data --freqaimodel <model> --config <config with freqai + exchange>
  3. When calling programmatically, construct DataProvider with a real Exchange instance (dp = DataProvider(config, exchange)) before calling the helper

Example fix

# before (script)
dp = DataProvider(config, None)  # no exchange
download_all_data_for_training(dp, config)

# after
exchange = ExchangeResolver.load_exchange(config, validate=True)
dp = DataProvider(config, exchange)
download_all_data_for_training(dp, config)
Defensive patterns

Strategy: validation

Validate before calling

# Programmatic guard before downloading freqAI training data
assert dp._exchange is not None, (
    'DataProvider has no exchange - load one via ExchangeResolver first')

Type guard

def dataprovider_has_exchange(dp) -> bool:
    return getattr(dp, '_exchange', None) is not None

Prevention

When it happens

Trigger: Calling freqtrade freqai commands that lead to download_all_data_for_training() (e.g. download-data with --freqaimodel, or start-up data preparation) with a config whose exchange section is missing or not instantiated; or invoking the utility programmatically with a DataProvider built with exchange=None.

Common situations: Config lacks the 'exchange' block or has an empty name; running data download utilities from a script with a DataProvider meant for backtesting; exchange initialization failed earlier and the error surfaces here first.

Related errors


AI-assisted analysis of freqtrade/freqtrade@1c8edfe4d1 (2026-08-15). Data as JSON: /api/errors/95445e755950c7ca. Report an issue: GitHub.