Eurostat

Surveys

Introduction

The Business and Consumer Surveys dataset by Eurostat tracks the five monthly confidence surveys the European Commission runs across households, industry, construction, retail and services. The data covers 35 European economies, starts in January 1980, and is delivered on a monthly frequency. This dataset is created by processing Eurostat's public dissemination API.

The surveys are the earliest read of the European economy available. They measure expectations rather than outcomes, so they are released before the month they describe has even finished, ahead of every hard indicator. European data moves the European Central Bank, and through it euro area rates, the euro itself and European equity indices, so a signal that leads the measured statistics by a month leads the market reaction with it. The price expectation questions, carried in four of the five surveys, are the earliest inflation signal on the platform.

For more information about the Surveys dataset, including CLI commands and pricing, see the dataset listing.

About the Provider

Eurostat is the statistical office of the European Union, based in Luxembourg and operating since 1953. Its role is to produce statistics that are comparable across member states, which is what makes a single European reading possible rather than 27 national ones computed differently. Eurostat publishes through a free dissemination API that requires no key and no registration. The confidence surveys themselves are collected by the European Commission's Directorate-General for Economic and Financial Affairs, which runs the joint harmonised programme the member states report into.

QuantConnect processes and caches these surveys so they reach your algorithm on their publication date rather than at the close of the month they measure, which is what keeps a backtest from reading a figure before it existed.

Getting Started

The following snippet demonstrates how to request data from the Business and Consumer Surveys dataset:

self.consumer = self.add_data(EurostatConsumerSurvey, Eurostat.Economies.GERMANY, Resolution.DAILY).symbol
self.industry = self.add_data(EurostatIndustrySurvey, Eurostat.Economies.EURO_AREA, Resolution.DAILY).symbol
_consumer = AddData<EurostatConsumerSurvey>(Eurostat.Economies.Germany, Resolution.Daily).Symbol;
_industry = AddData<EurostatIndustrySurvey>(Eurostat.Economies.EuroArea, Resolution.Daily).Symbol;

Data Summary

The following table describes the dataset properties:

PropertyValue
Start DateJanuary 1980
Data Points64,137
Asset Coverage35 European economies
Data DensitySparse
ResolutionDaily*
TimezoneBrussels

* Monthly data we fetch daily.

Requesting Data

To add Business and Consumer Surveys data to your algorithm, call the AddDataadd_data method. The dataset is unlinked, so instead of a security Symbol you pass the geo code of the economy you want. Save a reference to the dataset Symbol so you can access the data later in your algorithm.

class EurostatSurveysDataAlgorithm(QCAlgorithm):
    def initialize(self) -> None:
        self.set_start_date(2018, 1, 1)
        self.set_end_date(2021, 3, 31)
        self.set_cash(100000)

        self.equity = self.add_equity("SPY", Resolution.DAILY).symbol

        self.consumer = self.add_data(EurostatConsumerSurvey, Eurostat.Economies.GERMANY, Resolution.DAILY).symbol
        self.industry = self.add_data(EurostatIndustrySurvey, Eurostat.Economies.GERMANY, Resolution.DAILY).symbol
        self.services = self.add_data(EurostatServicesSurvey, Eurostat.Economies.GERMANY, Resolution.DAILY).symbol
public class EurostatSurveysDataAlgorithm : QCAlgorithm
{
    private Symbol _equity, _consumer, _industry, _services;

    public override void Initialize()
    {
        SetStartDate(2018, 1, 1);
        SetEndDate(2021, 3, 31);
        SetCash(100000);

        _equity = AddEquity("SPY", Resolution.Daily).Symbol;

        _consumer = AddData<EurostatConsumerSurvey>(Eurostat.Economies.Germany, Resolution.Daily).Symbol;
        _industry = AddData<EurostatIndustrySurvey>(Eurostat.Economies.Germany, Resolution.Daily).Symbol;
        _services = AddData<EurostatServicesSurvey>(Eurostat.Economies.Germany, Resolution.Daily).Symbol;
    }
}

Subscribe to as many surveys as you need for the same economy. The surveys describe economies and are not tradeable, so add a separate tradeable security if you want to place orders.

Accessing Data

To get the current Business and Consumer Surveys data, index the current Slice with the dataset Symbol. Slice objects deliver unique events to your algorithm as they happen, but the Slice may not contain data for your dataset at every time step. The surveys are monthly, so most days carry no new data. To avoid issues, check if the Slice contains the data you want before you index it, and check the property you want against nullNone before you act on it.

def on_data(self, slice: Slice) -> None:
    data = slice.get(EurostatConsumerSurvey)
    if self.consumer in data:
        data_point = data[self.consumer]
        if data_point.consumer_confidence is not None:
            self.log(f"{self.consumer} consumer confidence at {slice.time}: {data_point.consumer_confidence}")
public override void OnData(Slice slice)
{
    var data = slice.Get<EurostatConsumerSurvey>();
    if (data.ContainsKey(_consumer))
    {
        var dataPoint = data[_consumer];
        if (dataPoint.ConsumerConfidence.HasValue)
        {
            Log($"{_consumer} consumer confidence at {slice.Time}: {dataPoint.ConsumerConfidence}");
        }
    }
}

To iterate through all of the economies subscribed to a survey in the current Slice, call the Getget method.

def on_data(self, slice: Slice) -> None:
    for dataset_symbol, data_point in slice.get(EurostatIndustrySurvey).items():
        self.log(f"{dataset_symbol} industrial confidence at {slice.time}: {data_point.industrial_confidence}")
public override void OnData(Slice slice)
{
    foreach (var kvp in slice.Get<EurostatIndustrySurvey>())
    {
        var datasetSymbol = kvp.Key;
        var dataPoint = kvp.Value;
        Log($"{datasetSymbol} industrial confidence at {slice.Time}: {dataPoint.IndustrialConfidence}");
    }
}

The Value property of each class is that survey's own confidence indicator.

Historical Data

To get historical Business and Consumer Surveys data, call the Historyhistory method with the dataset Symbol. If there is no data in the period you request, the history result is empty. The surveys are monthly, so ask for a period rather than a bar count: a count is read as daily bars, and 60 of those return only the two surveys published inside them. Five years is 1,825 days, which returns 60 points.

# DataFrames
consumer_history_df = self.history(self.consumer, timedelta(days=1825), Resolution.DAILY)
industry_history_df = self.history(self.industry, timedelta(days=1825), Resolution.DAILY)
history_df = self.history([self.consumer, self.industry], timedelta(days=1825), Resolution.DAILY)

# Dataset objects
consumer_history_bars = self.history[EurostatConsumerSurvey](self.consumer, timedelta(days=1825), Resolution.DAILY)
industry_history_bars = self.history[EurostatIndustrySurvey](self.industry, timedelta(days=1825), Resolution.DAILY)
// Dataset objects
var consumerHistory = History<EurostatConsumerSurvey>(_consumer, TimeSpan.FromDays(1825), Resolution.Daily);
var industryHistory = History<EurostatIndustrySurvey>(_industry, TimeSpan.FromDays(1825), Resolution.Daily);

// Slice objects
var history = History(new[] {_consumer, _industry}, TimeSpan.FromDays(1825), Resolution.Daily);

For more information about historical data, see History Requests.

Remove Subscriptions

To remove your subscription to a Business and Consumer Surveys class, call the RemoveSecurityremove_security method.

self.remove_security(self.consumer)
RemoveSecurity(_consumer);

Supported Economies

The ticker of a subscription is the Eurostat geo code of the economy. The Eurostat.Economies helper gives each one a readable name that resolves to its code. The surveys cover the following 35 economies:

EconomyGeo codeConstant
Aggregates
Euro areaEA21Eurostat.Economies.EuroAreaEurostat.Economies.EURO_AREA
Euro area (20 countries)EA20Eurostat.Economies.EuroArea20Eurostat.Economies.EURO_AREA_20
European UnionEU27_2020Eurostat.Economies.EuropeanUnionEurostat.Economies.EUROPEAN_UNION
Countries
AlbaniaALEurostat.Economies.AlbaniaEurostat.Economies.ALBANIA
AustriaATEurostat.Economies.AustriaEurostat.Economies.AUSTRIA
BelgiumBEEurostat.Economies.BelgiumEurostat.Economies.BELGIUM
BulgariaBGEurostat.Economies.BulgariaEurostat.Economies.BULGARIA
CroatiaHREurostat.Economies.CroatiaEurostat.Economies.CROATIA
CyprusCYEurostat.Economies.CyprusEurostat.Economies.CYPRUS
CzechiaCZEurostat.Economies.CzechiaEurostat.Economies.CZECHIA
DenmarkDKEurostat.Economies.DenmarkEurostat.Economies.DENMARK
EstoniaEEEurostat.Economies.EstoniaEurostat.Economies.ESTONIA
FinlandFIEurostat.Economies.FinlandEurostat.Economies.FINLAND
FranceFREurostat.Economies.FranceEurostat.Economies.FRANCE
GermanyDEEurostat.Economies.GermanyEurostat.Economies.GERMANY
GreeceELEurostat.Economies.GreeceEurostat.Economies.GREECE
HungaryHUEurostat.Economies.HungaryEurostat.Economies.HUNGARY
IrelandIEEurostat.Economies.IrelandEurostat.Economies.IRELAND
ItalyITEurostat.Economies.ItalyEurostat.Economies.ITALY
LatviaLVEurostat.Economies.LatviaEurostat.Economies.LATVIA
LithuaniaLTEurostat.Economies.LithuaniaEurostat.Economies.LITHUANIA
LuxembourgLUEurostat.Economies.LuxembourgEurostat.Economies.LUXEMBOURG
MaltaMTEurostat.Economies.MaltaEurostat.Economies.MALTA
MontenegroMEEurostat.Economies.MontenegroEurostat.Economies.MONTENEGRO
NetherlandsNLEurostat.Economies.NetherlandsEurostat.Economies.NETHERLANDS
North MacedoniaMKEurostat.Economies.NorthMacedoniaEurostat.Economies.NORTH_MACEDONIA
PolandPLEurostat.Economies.PolandEurostat.Economies.POLAND
PortugalPTEurostat.Economies.PortugalEurostat.Economies.PORTUGAL
RomaniaROEurostat.Economies.RomaniaEurostat.Economies.ROMANIA
SerbiaRSEurostat.Economies.SerbiaEurostat.Economies.SERBIA
SlovakiaSKEurostat.Economies.SlovakiaEurostat.Economies.SLOVAKIA
SloveniaSIEurostat.Economies.SloveniaEurostat.Economies.SLOVENIA
SpainESEurostat.Economies.SpainEurostat.Economies.SPAIN
SwedenSEEurostat.Economies.SwedenEurostat.Economies.SWEDEN
TurkiyeTREurostat.Economies.TurkiyeEurostat.Economies.TURKIYE

EA21 is the current euro area composition and EA20 the previous one, and the surveys stop publishing EA20 in December 2025. The five surveys share a release date, so one round delivers the whole economy at once.

Example Applications

The Business and Consumer Surveys dataset lets you read the European economy before it shows up in any measured statistic. Examples include the following strategies:

  • Timing exposure to European equities or the euro on the direction of consumer confidence, the earliest reading of the five.
  • Reading price expectations across industry, construction, retail and services as an inflation signal that leads both producer and consumer prices.
  • Watching industrial order books, and export order books in particular, as a lead on industrial production and on external demand.
  • Comparing confidence across economies, for example German industry against Spanish, to rotate country exposure.
  • Combining the five surveys into a breadth measure of how much of the economy is improving at once, rather than reading any single sector.

Classic Algorithm Example

The following example algorithm reads German consumer confidence as a risk-on signal and holds SPY while households are turning less pessimistic, stepping aside when they are not. It also logs what manufacturers expect to charge, which is pipeline inflation months before a price index measures it.

from AlgorithmImports import *

class EurostatSurveysExampleAlgorithm(QCAlgorithm):

    def initialize(self):
        self.set_start_date(2018, 1, 1)
        self.set_end_date(2021, 3, 31)
        self.set_cash(100000)

        self.equity = self.add_equity("SPY", Resolution.DAILY).symbol

        self.consumer = self.add_data(EurostatConsumerSurvey, Eurostat.Economies.GERMANY, Resolution.DAILY).symbol
        self.industry = self.add_data(EurostatIndustrySurvey, Eurostat.Economies.GERMANY, Resolution.DAILY).symbol

        self.previous_confidence = None

    def on_data(self, slice):
        industry = slice.get(EurostatIndustrySurvey)
        if self.industry in industry:
            data_point = industry[self.industry]
            self.debug(f"Industrial confidence: {data_point.industrial_confidence}, selling price expectations: {data_point.selling_price_expectation}")

        consumer = slice.get(EurostatConsumerSurvey)
        if self.consumer not in consumer:
            return

        confidence = consumer[self.consumer].consumer_confidence
        if confidence is None:
            return

        # Households turning less pessimistic is the risk-on read.
        if self.previous_confidence is not None:
            if confidence > self.previous_confidence:
                self.set_holdings(self.equity, 1)
            else:
                self.liquidate(self.equity)

        self.previous_confidence = confidence
public class EurostatSurveysExampleAlgorithm : QCAlgorithm
{
    private Symbol _equity, _consumer, _industry;
    private decimal? _previousConfidence;

    public override void Initialize()
    {
        SetStartDate(2018, 1, 1);
        SetEndDate(2021, 3, 31);
        SetCash(100000);

        _equity = AddEquity("SPY", Resolution.Daily).Symbol;

        _consumer = AddData<EurostatConsumerSurvey>(Eurostat.Economies.Germany, Resolution.Daily).Symbol;
        _industry = AddData<EurostatIndustrySurvey>(Eurostat.Economies.Germany, Resolution.Daily).Symbol;
    }

    public override void OnData(Slice slice)
    {
        var industry = slice.Get<EurostatIndustrySurvey>();
        if (industry.ContainsKey(_industry))
        {
            var dataPoint = industry[_industry];
            Debug($"Industrial confidence: {dataPoint.IndustrialConfidence}, selling price expectations: {dataPoint.SellingPriceExpectation}");
        }

        var consumer = slice.Get<EurostatConsumerSurvey>();
        if (!consumer.ContainsKey(_consumer))
        {
            return;
        }

        var confidence = consumer[_consumer].ConsumerConfidence;
        if (!confidence.HasValue)
        {
            return;
        }

        // Households turning less pessimistic is the risk-on read.
        if (_previousConfidence.HasValue)
        {
            if (confidence > _previousConfidence)
            {
                SetHoldings(_equity, 1);
            }
            else
            {
                Liquidate(_equity);
            }
        }

        _previousConfidence = confidence;
    }
}

Framework Algorithm Example

The following example algorithm trades a manually selected universe from the confidence surveys. An alpha model subscribes to the German consumer and industry surveys, then emits an up insight only when households and manufacturers are turning more confident in the same round, which is a breadth reading rather than a single sector one.

from AlgorithmImports import *

class EurostatSurveysFrameworkAlgorithm(QCAlgorithm):

    def initialize(self):
        self.set_start_date(2018, 1, 1)
        self.set_end_date(2021, 3, 31)
        self.set_cash(100000)

        self.universe_settings.resolution = Resolution.DAILY

        symbols = [Symbol.create("SPY", SecurityType.EQUITY, Market.USA)]
        self.set_universe_selection(ManualUniverseSelectionModel(symbols))

        self.add_alpha(EurostatConfidenceAlphaModel(self))

        self.set_portfolio_construction(EqualWeightingPortfolioConstructionModel())
        self.set_execution(ImmediateExecutionModel())


class EurostatConfidenceAlphaModel(AlphaModel):
    """Emits insights from the direction of European confidence, read across households and industry."""

    def __init__(self, algorithm):
        self._consumer = algorithm.add_data(EurostatConsumerSurvey, Eurostat.Economies.GERMANY, Resolution.DAILY).symbol
        self._industry = algorithm.add_data(EurostatIndustrySurvey, Eurostat.Economies.GERMANY, Resolution.DAILY).symbol

        history = algorithm.history(EurostatConsumerSurvey, self._consumer, timedelta(days=1825), Resolution.DAILY)
        algorithm.debug(f"Got {len(history)} historical consumer survey rows")

        self._previous_consumer = None
        self._previous_industry = None
        self._symbols = []

    def update(self, algorithm, data):
        insights = []

        consumer = data.get(EurostatConsumerSurvey)
        if self._consumer not in consumer:
            return insights

        confidence = consumer[self._consumer].consumer_confidence
        if confidence is None:
            return insights

        # The industry survey shares its release date with the consumer one, so the confirmation
        # is read from the same round.
        industry_point = algorithm.securities[self._industry].cache.get_data(EurostatIndustrySurvey)
        industrial = industry_point.industrial_confidence if industry_point else None

        if self._previous_consumer is not None:
            improving = confidence > self._previous_consumer
            if improving and industrial is not None and self._previous_industry is not None:
                improving = industrial > self._previous_industry

            direction = InsightDirection.UP if improving else InsightDirection.FLAT
            insights = [Insight.price(symbol, timedelta(days=30), direction) for symbol in self._symbols]

        self._previous_consumer = confidence
        if industrial is not None:
            self._previous_industry = industrial

        return insights

    def on_securities_changed(self, algorithm, changes):
        for security in changes.added_securities:
            self._symbols.append(security.symbol)

        for security in changes.removed_securities:
            if security.symbol in self._symbols:
                self._symbols.remove(security.symbol)
public class EurostatSurveysFrameworkAlgorithm : QCAlgorithm
{
    public override void Initialize()
    {
        SetStartDate(2018, 1, 1);
        SetEndDate(2021, 3, 31);
        SetCash(100000);

        UniverseSettings.Resolution = Resolution.Daily;

        var symbols = new[] { QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA) };
        SetUniverseSelection(new ManualUniverseSelectionModel(symbols));

        AddAlpha(new EurostatConfidenceAlphaModel(this));

        SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
        SetExecution(new ImmediateExecutionModel());
    }
}

public class EurostatConfidenceAlphaModel : AlphaModel
{
    private readonly Symbol _consumer;
    private readonly Symbol _industry;
    private readonly List<Symbol> _symbols = new();

    private decimal? _previousConsumer;
    private decimal? _previousIndustry;

    public EurostatConfidenceAlphaModel(QCAlgorithm algorithm)
    {
        _consumer = algorithm.AddData<EurostatConsumerSurvey>(Eurostat.Economies.Germany, Resolution.Daily).Symbol;
        _industry = algorithm.AddData<EurostatIndustrySurvey>(Eurostat.Economies.Germany, Resolution.Daily).Symbol;

        var history = algorithm.History<EurostatConsumerSurvey>(_consumer, TimeSpan.FromDays(1825), Resolution.Daily);
        algorithm.Debug($"Got {history.Count()} historical consumer survey rows");
    }

    public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
    {
        var insights = new List<Insight>();

        var consumer = data.Get<EurostatConsumerSurvey>();
        if (!consumer.ContainsKey(_consumer))
        {
            return insights;
        }

        var confidence = consumer[_consumer].ConsumerConfidence;
        if (!confidence.HasValue)
        {
            return insights;
        }

        // The industry survey shares its release date with the consumer one, so the confirmation
        // is read from the same round.
        var industryPoint = algorithm.Securities[_industry].Cache.GetData<EurostatIndustrySurvey>();
        var industrial = industryPoint?.IndustrialConfidence;

        if (_previousConsumer.HasValue)
        {
            var improving = confidence > _previousConsumer;
            if (improving && industrial.HasValue && _previousIndustry.HasValue)
            {
                improving = industrial > _previousIndustry;
            }

            var direction = improving ? InsightDirection.Up : InsightDirection.Flat;
            insights = _symbols.Select(symbol => Insight.Price(symbol, TimeSpan.FromDays(30), direction)).ToList();
        }

        _previousConsumer = confidence;
        if (industrial.HasValue)
        {
            _previousIndustry = industrial;
        }

        return insights;
    }

    public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
    {
        foreach (var security in changes.AddedSecurities)
        {
            _symbols.Add(security.Symbol);
        }

        foreach (var security in changes.RemovedSecurities)
        {
            _symbols.Remove(security.Symbol);
        }
    }
}

Data Point Attributes

The Business and Consumer Surveys dataset provides EurostatConsumerSurvey, EurostatIndustrySurvey, EurostatConstructionSurvey, EurostatRetailSurvey and EurostatServicesSurvey objects. Every property is nullable: Eurostat publishes a given question for some economies and not others, so a column can be empty for an entire economy.

EurostatConsumerSurvey

EurostatConsumerSurvey objects have the following attributes:

EurostatIndustrySurvey

EurostatIndustrySurvey objects have the following attributes:

EurostatConstructionSurvey

EurostatConstructionSurvey objects have the following attributes:

EurostatRetailSurvey

EurostatRetailSurvey objects have the following attributes:

EurostatServicesSurvey

EurostatServicesSurvey objects have the following attributes:

You can also see our Videos. You can also get in touch with us via Discord.

Did you find this page helpful?

Contribute to the documentation: